From cdf209eb02d6534bad87d8948ede1148ba04419e Mon Sep 17 00:00:00 2001 From: bbradson <76005458+bbradson@users.noreply.github.com> Date: Sat, 3 Jun 2023 20:10:58 +0200 Subject: [PATCH] Added FisheryLib.Collections.FishTable and Mono.Cecil extension methods A bit of refactoring has been done too --- 1.3/Assemblies/1Fishery.dll | Bin 200704 -> 222208 bytes 1.3/Assemblies/1Fishery.pdb | Bin 0 -> 92556 bytes 1.3/Assemblies/IndexRange.dll | Bin 11776 -> 0 bytes 1.4/Assemblies/1Fishery.dll | Bin 200704 -> 282624 bytes 1.4/Assemblies/1Fishery.pdb | Bin 0 -> 115456 bytes 1.4/Assemblies/IndexRange.dll | Bin 11776 -> 0 bytes About/About.xml | 1 - README.md | 3 +- Source/FisheryLib/.editorconfig | 43 +- Source/FisheryLib/Aliases.cs | 3 + Source/FisheryLib/ArraySortHelper.cs | 346 ++-- Source/FisheryLib/BoolExtensions.cs | 20 +- Source/FisheryLib/Cecil/CecilExtensions.cs | 559 +++++++ .../Cecil/CecilReflectionExtensions.cs | 25 + .../FisheryLib/Cecil/ReflectionExtensions.cs | 84 + Source/FisheryLib/CollectionExtensions.cs | 471 +++++- Source/FisheryLib/Collections/FishSet.cs | 862 ++++++++++ Source/FisheryLib/Collections/FishTable.cs | 1475 +++++++++++++++++ Source/FisheryLib/Collections/NibbleArray.cs | 62 + .../FisheryLib/Collections/StructFishTable.cs | 1050 ++++++++++++ Source/FisheryLib/Convert.cs | 10 +- .../Attributes/UnscopedRefAttribute.cs | 38 + .../Diagnostics/Extensions/TypeExtensions.cs | 31 +- .../Extensions/ValueTypeExtensions.cs | 13 +- .../Diagnostics/Generated/Guard.Collection.tt | 234 +-- .../Generated/Guard.Comparable.Numeric.tt | 92 +- .../FisheryLib/Diagnostics/Generated/Guard.md | 24 +- .../Generated/ThrowHelper.Collection.tt | 50 +- .../Diagnostics/Generated/TypeInfo.ttinclude | 14 +- .../FisheryLib/Diagnostics/Guard.Boolean.cs | 16 +- .../Diagnostics/Guard.Comparable.Generic.cs | 63 +- .../Diagnostics/Guard.Comparable.Numeric.cs | 52 +- Source/FisheryLib/Diagnostics/Guard.IO.cs | 10 +- Source/FisheryLib/Diagnostics/Guard.String.cs | 53 +- Source/FisheryLib/Diagnostics/Guard.Tasks.cs | 28 +- Source/FisheryLib/Diagnostics/Guard.cs | 79 +- .../Guard.Collection.Generic.ThrowHelper.cs | 17 +- .../Guard.Comparable.Generic.ThrowHelper.cs | 71 +- .../Guard.Comparable.Numeric.ThrowHelper.cs | 52 +- .../Internals/Guard.IO.ThrowHelper.cs | 19 +- .../Internals/Guard.String.ThrowHelper.cs | 71 +- .../Internals/Guard.Tasks.ThrowHelper.cs | 52 +- .../Internals/Guard.ThrowHelper.cs | 80 +- .../Diagnostics/ThrowHelper.Generic.cs | 129 +- Source/FisheryLib/Diagnostics/ThrowHelper.cs | 129 +- Source/FisheryLib/Equality.cs | 7 +- Source/FisheryLib/FishPatch.cs | 3 +- Source/FisheryLib/FishTranspiler.cs | 1346 ++++++++++----- Source/FisheryLib/Fishery.cs | 15 +- Source/FisheryLib/Fishery.csproj | 133 +- .../FisheryLib/FisheryPatchClassProcessor.cs | 3 +- Source/FisheryLib/FunctionPointers/Convert.cs | 253 ++- Source/FisheryLib/FunctionPointers/Equals.cs | 131 +- .../FunctionPointers/EqualsByRef.cs | 128 +- .../FunctionPointers/GetHashCode.cs | 96 +- .../FunctionPointers/GetHashCodeByRef.cs | 81 +- .../FunctionPointers/MethodFactory.cs | 393 +++++ Source/FisheryLib/HarmonyPatchExtensions.cs | 3 +- Source/FisheryLib/HashCode.cs | 22 +- Source/FisheryLib/InfixMethod.cs | 3 +- Source/FisheryLib/Log.cs | 22 +- Source/FisheryLib/MemoryMarshal.cs | 119 +- Source/FisheryLib/ReadOnlySpanEnumerable.cs | 7 +- Source/FisheryLib/ReadOnlySpanExtensions.cs | 43 +- Source/FisheryLib/Reflection.cs | 468 +++++- Source/FisheryLib/SingletonFactory.cs | 24 +- Source/FisheryLib/SpanEnumerable.cs | 14 +- Source/FisheryLib/SpanExtensions.cs | 311 ++-- Source/FisheryLib/StackList.cs | 88 + Source/FisheryLib/StopwatchExtensions.cs | 27 + Source/FisheryLib/Utility.cs | 28 +- Source/FisheryLib/Utility/FishMath.cs | 44 + 72 files changed, 8145 insertions(+), 2098 deletions(-) create mode 100644 1.3/Assemblies/1Fishery.pdb delete mode 100644 1.3/Assemblies/IndexRange.dll create mode 100644 1.4/Assemblies/1Fishery.pdb delete mode 100644 1.4/Assemblies/IndexRange.dll create mode 100644 Source/FisheryLib/Cecil/CecilExtensions.cs create mode 100644 Source/FisheryLib/Cecil/CecilReflectionExtensions.cs create mode 100644 Source/FisheryLib/Cecil/ReflectionExtensions.cs create mode 100644 Source/FisheryLib/Collections/FishSet.cs create mode 100644 Source/FisheryLib/Collections/FishTable.cs create mode 100644 Source/FisheryLib/Collections/NibbleArray.cs create mode 100644 Source/FisheryLib/Collections/StructFishTable.cs create mode 100644 Source/FisheryLib/Diagnostics/Attributes/UnscopedRefAttribute.cs create mode 100644 Source/FisheryLib/FunctionPointers/MethodFactory.cs create mode 100644 Source/FisheryLib/StackList.cs create mode 100644 Source/FisheryLib/StopwatchExtensions.cs create mode 100644 Source/FisheryLib/Utility/FishMath.cs diff --git a/1.3/Assemblies/1Fishery.dll b/1.3/Assemblies/1Fishery.dll index bfc5879ce4204758b4a259f9f581988e019cae2a..ae2687724ce841e5e09af715063582b5c9dedc66 100644 GIT binary patch literal 222208 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 KFMvOU8Tem7ESn7g literal 200704 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 z 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 G;J*RZAaFJS diff --git a/1.3/Assemblies/1Fishery.pdb b/1.3/Assemblies/1Fishery.pdb new file mode 100644 index 0000000000000000000000000000000000000000..efc3455c7d97450f17bb0e5cdc0919f611d87ff4 GIT binary patch literal 92556 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 literal 0 HcmV?d00001 diff --git a/1.3/Assemblies/IndexRange.dll b/1.3/Assemblies/IndexRange.dll deleted file mode 100644 index be06f22358f3e19b19ac7aa206a57c6fc104ff47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11776 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 BKYRcH literal 200704 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

EZKx9wZa{;*E$hw|2EV7pzV$evS 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

  • Ludeon.RimWorld
  • me.samboycoding.betterloading
  • -
  • zetrith.prepatcher
  • brrainz.harmony
  • diff --git a/README.md b/README.md index c067c6f..6ed94ad 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # Fishery Modding Library for RimWorld. Used by Performance Fish. -Useful functions include various abstractions around IL in FishTranspiler, to make writing of transpilers easier and more robust. A couple collections like Dictionary and Span have extension methods for fast and convenient lookups. Some functionalities of Microsoft's Community Toolkit are included, expanded upon and modified to better fit Unity. Equality includes generic extension methods to use in place of Equals on structs without memory allocations. Convert provides a faster, generic alternative to System.Convert.ToType. FisheryLib.Reflection provides a couple reflection helpers, Aliases has a methodof function intended to be utilized with `global using static Aliases` to directly retrieve method infos from static method groups. +Useful functions include various abstractions around IL in FishTranspiler, to make writing of transpilers easier and more robust. A couple collections like Dictionary and Span have extension methods for fast and convenient lookups. Some functionalities of Microsoft's Community Toolkit are included, expanded upon and modified to better fit Unity. Equality includes generic extension methods to use in place of Equals on structs without memory allocations. Convert provides a faster, generic alternative to System.Convert.ToType. FisheryLib.Reflection provides a couple reflection helpers, Aliases has a methodof function intended to be utilized with `global using static Aliases` to directly retrieve method infos from static method groups. +Additionally this includes a fast and much more versatile System.Collections.Generic.Dictionary replacement in FisheryLib.Collections.FishTable, loosely based on Malte Skarupke's ska::bytell_hash_map, as well as several extensions and helpers for Mono.Cecil, which is utilized by Prepatcher. \ No newline at end of file diff --git a/Source/FisheryLib/.editorconfig b/Source/FisheryLib/.editorconfig index 14c2131..729881f 100644 --- a/Source/FisheryLib/.editorconfig +++ b/Source/FisheryLib/.editorconfig @@ -1,6 +1,6 @@ [*.cs] -file_header_template = Copyright (c) 2022 bradson\nThis Source Code Form is subject to the terms of the Mozilla Public\nLicense, v. 2.0. If a copy of the MPL was not distributed with this\nfile, You can obtain one at https://mozilla.org/MPL/2.0/. +file_header_template = Copyright (c) 2022 bradson\nThis Source Code Form is subject to the terms of the Mozilla Public\nLicense, v.2.0.If a copy of the MPL was not distributed with this\nfile, You can obtain one at https://mozilla.org/MPL/2.0/. # CA2211: Non-constant fields should not be visible dotnet_diagnostic.CA2211.severity = none @@ -47,6 +47,7 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_namespace_match_folder = true:suggestion + [*.cs] #### Naming styles #### @@ -72,27 +73,27 @@ dotnet_naming_symbols.constant.required_modifiers = const dotnet_naming_symbols.private_or_protected_field.applicable_kinds = field dotnet_naming_symbols.private_or_protected_field.applicable_accessibilities = private, protected, protected_internal, private_protected -dotnet_naming_symbols.private_or_protected_field.required_modifiers = +dotnet_naming_symbols.private_or_protected_field.required_modifiers = dotnet_naming_symbols.public_or_internal_field.applicable_kinds = field dotnet_naming_symbols.public_or_internal_field.applicable_accessibilities = public, internal -dotnet_naming_symbols.public_or_internal_field.required_modifiers = +dotnet_naming_symbols.public_or_internal_field.required_modifiers = # Naming styles -dotnet_naming_style.all_upper.required_prefix = -dotnet_naming_style.all_upper.required_suffix = +dotnet_naming_style.all_upper.required_prefix = +dotnet_naming_style.all_upper.required_suffix = dotnet_naming_style.all_upper.word_separator = _ dotnet_naming_style.all_upper.capitalization = all_upper dotnet_naming_style.camel_case_with__.required_prefix = _ -dotnet_naming_style.camel_case_with__.required_suffix = -dotnet_naming_style.camel_case_with__.word_separator = +dotnet_naming_style.camel_case_with__.required_suffix = +dotnet_naming_style.camel_case_with__.word_separator = dotnet_naming_style.camel_case_with__.capitalization = camel_case -dotnet_naming_style.camel_case.required_prefix = -dotnet_naming_style.camel_case.required_suffix = -dotnet_naming_style.camel_case.word_separator = +dotnet_naming_style.camel_case.required_prefix = +dotnet_naming_style.camel_case.required_suffix = +dotnet_naming_style.camel_case.word_separator = dotnet_naming_style.camel_case.capitalization = camel_case dotnet_diagnostic.CA1805.severity = none csharp_style_prefer_tuple_swap = true:suggestion @@ -138,31 +139,31 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case dotnet_diagnostic.CA1838.severity = suggestion dotnet_diagnostic.CA1848.severity = suggestion diff --git a/Source/FisheryLib/Aliases.cs b/Source/FisheryLib/Aliases.cs index fbaade2..bbc7b5f 100644 --- a/Source/FisheryLib/Aliases.cs +++ b/Source/FisheryLib/Aliases.cs @@ -5,12 +5,15 @@ global using static FisheryLib.Aliases; using System.Runtime.CompilerServices; +using JetBrains.Annotations; namespace FisheryLib; +[PublicAPI] [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "alias")] public static class Aliases { [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable once InconsistentNaming public static MethodInfo methodof(Delegate method) => method.Method; } \ No newline at end of file diff --git a/Source/FisheryLib/ArraySortHelper.cs b/Source/FisheryLib/ArraySortHelper.cs index 7e91c41..d1253dc 100644 --- a/Source/FisheryLib/ArraySortHelper.cs +++ b/Source/FisheryLib/ArraySortHelper.cs @@ -1,18 +1,21 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using UnityEngine; +// ReSharper disable PossibleUnintendedReferenceComparison namespace FisheryLib; + #region ArraySortHelper for single arrays +#pragma warning disable CS8500 internal sealed class ArraySortHelper : IArraySortHelper { public static IArraySortHelper Default { get; } = CreateArraySortHelper(); private static IArraySortHelper CreateArraySortHelper() => typeof(IComparable).IsAssignableFrom(typeof(T)) - ? (IArraySortHelper)Activator.CreateInstance(typeof(GenericArraySortHelper<>).MakeGenericType(typeof(T))) - : new ArraySortHelper(); + ? (IArraySortHelper)Activator.CreateInstance(typeof(GenericArraySortHelper<>).MakeGenericType(typeof(T))) + : new ArraySortHelper(); #region IArraySortHelper Members @@ -61,9 +64,7 @@ internal sealed class ArraySortHelper : IArraySortHelper Debug.Assert(i != j); if (comparer(keys[i], keys[j]) > 0) - { (keys[j], keys[i]) = (keys[i], keys[j]); - } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -79,9 +80,7 @@ internal sealed class ArraySortHelper : IArraySortHelper Debug.Assert(comparer != null); if (keys.Length > 1) - { IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer!); - } } private static void IntroSort(Span keys, int depthLimit, Comparison comparer) @@ -95,7 +94,6 @@ internal sealed class ArraySortHelper : IArraySortHelper { if (partitionSize <= SortUtils.INTROSORT_SIZE_THRESHOLD) { - if (partitionSize == 2) { SwapIfGreater(keys, comparer!, 0, 1); @@ -119,6 +117,7 @@ internal sealed class ArraySortHelper : IArraySortHelper HeapSort(keys[..partitionSize], comparer!); return; } + depthLimit--; var p = PickPivotAndPartition(keys[..partitionSize], comparer!); @@ -141,12 +140,14 @@ internal sealed class ArraySortHelper : IArraySortHelper // Sort lo, mid and hi appropriately, then pick mid as the pivot. SwapIfGreater(keys, comparer!, 0, middle); // swap the low with the mid point - SwapIfGreater(keys, comparer!, 0, hi); // swap the low with the high + SwapIfGreater(keys, comparer!, 0, hi); // swap the low with the high SwapIfGreater(keys, comparer!, middle, hi); // swap the middle with the high var pivot = keys[middle]; Swap(keys, middle, hi - 1); - int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + int left = 0, + right = hi + - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. while (left < right) { @@ -163,9 +164,7 @@ internal sealed class ArraySortHelper : IArraySortHelper // Put pivot in the right location. if (left != hi - 1) - { Swap(keys, left, hi - 1); - } return left; } @@ -176,9 +175,7 @@ internal sealed class ArraySortHelper : IArraySortHelper var n = keys.Length; for (var i = n >> 1; i >= 1; i--) - { DownHeap(keys, i, n, comparer!); - } for (var i = n; i > 1; i--) { @@ -196,9 +193,7 @@ internal sealed class ArraySortHelper : IArraySortHelper { var child = 2 * i; if (child < n && comparer!(keys[child - 1], keys[child]) < 0) - { child++; - } if (!(comparer!(d, keys[child - 1]) < 0)) break; @@ -241,29 +236,25 @@ internal sealed class GenericArraySortHelper : IArraySortHelper { if (comparer == null || comparer == Comparer.Default) { - if (keys.Length > 1) - { - // For floating-point, do a pre-pass to move all NaNs to the beginning - // so that we can do an optimized comparison as part of the actual sort - // on the remainder of the values. - if (typeof(T) == typeof(double) || - typeof(T) == typeof(float)) - { - var nanLeft = SortUtils.MoveNansToFront(keys, default(Span)); - if (nanLeft == keys.Length) - { - return; - } - keys = keys[nanLeft..]; - } + if (keys.Length <= 1) + return; - IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); + // For floating-point, do a pre-pass to move all NaNs to the beginning + // so that we can do an optimized comparison as part of the actual sort + // on the remainder of the values. + if (typeof(T) == typeof(double) || typeof(T) == typeof(float)) + { + var nanLeft = SortUtils.MoveNansToFront(keys, default(Span)); + if (nanLeft == keys.Length) + return; + + keys = keys[nanLeft..]; } + + IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); } else - { ArraySortHelper.IntrospectiveSort(keys, comparer.Compare); - } } catch (IndexOutOfRangeException) { @@ -279,12 +270,10 @@ internal sealed class GenericArraySortHelper : IArraySortHelper /// Swaps the values in the two references if the first is greater than the second. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void SwapIfGreater(ref T i, ref T j) + private static void SwapIfGreater([AllowNull] ref T i, ref T j) { if (i != null && GreaterThan(ref i, ref j)) - { Swap(ref i, ref j); - } } /// Swaps the values in the two references, regardless of whether the two references are the same. @@ -333,6 +322,7 @@ internal sealed class GenericArraySortHelper : IArraySortHelper HeapSort(keys[..partitionSize]); return; } + depthLimit--; var p = PickPivotAndPartition(keys[..partitionSize]); @@ -343,7 +333,7 @@ internal sealed class GenericArraySortHelper : IArraySortHelper } } - private static int PickPivotAndPartition(Span keys) + private static unsafe int PickPivotAndPartition(Span keys) { Debug.Assert(keys.Length >= SortUtils.INTROSORT_SIZE_THRESHOLD); @@ -361,38 +351,39 @@ internal sealed class GenericArraySortHelper : IArraySortHelper Swap(ref middleRef, ref nextToLastRef); // Walk the left and right pointers, swapping elements as necessary, until they cross. + // ReSharper disable once RedundantSuppressNullableWarningExpression ref T leftRef = ref zeroRef!, rightRef = ref nextToLastRef!; while (Unsafe.IsAddressLessThan(ref leftRef, ref rightRef)) { if (pivot == null) { - while (Unsafe.IsAddressLessThan(ref leftRef!, ref nextToLastRef) && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) + while (Unsafe.IsAddressLessThan(ref leftRef!, ref nextToLastRef) + && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) ; - while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && (rightRef = ref Unsafe.Add(ref rightRef, -1)) != null) + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) + && (rightRef = ref Unsafe.Add(ref rightRef, -1)) != null) ; } else { - while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && GreaterThan(ref pivot, ref leftRef = ref Unsafe.Add(ref leftRef, 1))) + while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) + && GreaterThan(ref pivot, ref leftRef = ref Unsafe.Add(ref leftRef, 1))) ; - while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && LessThan(ref pivot, ref rightRef = ref Unsafe.Add(ref rightRef, -1))) + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) + && LessThan(ref pivot, ref rightRef = ref Unsafe.Add(ref rightRef, -1))) ; } if (!Unsafe.IsAddressLessThan(ref leftRef, ref rightRef!)) - { break; - } Swap(ref leftRef, ref rightRef); } // Put the pivot in the correct location. if (!Unsafe.AreSame(ref leftRef, ref nextToLastRef)) - { Swap(ref leftRef, ref nextToLastRef); - } - return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / Unsafe.SizeOf()); + return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / sizeof(T)); } private static void HeapSort(Span keys) @@ -401,9 +392,7 @@ internal sealed class GenericArraySortHelper : IArraySortHelper var n = keys.Length; for (var i = n >> 1; i >= 1; i--) - { DownHeap(keys, i, n); - } for (var i = n; i > 1; i--) { @@ -419,9 +408,7 @@ internal sealed class GenericArraySortHelper : IArraySortHelper { var child = 2 * i; if (child < n && (keys[child - 1] == null || LessThan(ref keys[child - 1], ref keys[child]))) - { child++; - } if (keys[child - 1] == null || !LessThan(ref d, ref keys[child - 1])) break; @@ -442,7 +429,8 @@ internal sealed class GenericArraySortHelper : IArraySortHelper var j = i; while (j >= 0 && (t == null || LessThan(ref t, ref Unsafe.Add(ref MemoryMarshal.GetReference(keys), j)))) { - Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = Unsafe.Add(ref MemoryMarshal.GetReference(keys), j); + Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) + = Unsafe.Add(ref MemoryMarshal.GetReference(keys), j); j--; } @@ -460,58 +448,34 @@ internal sealed class GenericArraySortHelper : IArraySortHelper [MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call private static bool LessThan(ref T left, ref T right) - => typeof(T) == typeof(byte) - ? (byte)(object)left < (byte)(object)right - : typeof(T) == typeof(sbyte) - ? (sbyte)(object)left < (sbyte)(object)right - : typeof(T) == typeof(ushort) - ? (ushort)(object)left < (ushort)(object)right - : typeof(T) == typeof(short) - ? (short)(object)left < (short)(object)right - : typeof(T) == typeof(uint) - ? (uint)(object)left < (uint)(object)right - : typeof(T) == typeof(int) - ? (int)(object)left < (int)(object)right - : typeof(T) == typeof(ulong) - ? (ulong)(object)left < (ulong)(object)right - : typeof(T) == typeof(long) - ? (long)(object)left < (long)(object)right - : typeof(T) == typeof(nuint) - ? (nuint)(object)left < (nuint)(object)right - : typeof(T) == typeof(nint) - ? (nint)(object)left < (nint)(object)right - : typeof(T) == typeof(float) - ? (float)(object)left < (float)(object)right - : typeof(T) == typeof(double) - ? (double)(object)left < (double)(object)right + => typeof(T) == typeof(byte) ? (byte)(object)left < (byte)(object)right + : typeof(T) == typeof(sbyte) ? (sbyte)(object)left < (sbyte)(object)right + : typeof(T) == typeof(ushort) ? (ushort)(object)left < (ushort)(object)right + : typeof(T) == typeof(short) ? (short)(object)left < (short)(object)right + : typeof(T) == typeof(uint) ? (uint)(object)left < (uint)(object)right + : typeof(T) == typeof(int) ? (int)(object)left < (int)(object)right + : typeof(T) == typeof(ulong) ? (ulong)(object)left < (ulong)(object)right + : typeof(T) == typeof(long) ? (long)(object)left < (long)(object)right + : typeof(T) == typeof(nuint) ? (nuint)(object)left < (nuint)(object)right + : typeof(T) == typeof(nint) ? (nint)(object)left < (nint)(object)right + : typeof(T) == typeof(float) ? (float)(object)left < (float)(object)right + : typeof(T) == typeof(double) ? (double)(object)left < (double)(object)right : left.CompareTo(right) < 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call private static bool GreaterThan(ref T left, ref T right) - => typeof(T) == typeof(byte) - ? (byte)(object)left > (byte)(object)right - : typeof(T) == typeof(sbyte) - ? (sbyte)(object)left > (sbyte)(object)right - : typeof(T) == typeof(ushort) - ? (ushort)(object)left > (ushort)(object)right - : typeof(T) == typeof(short) - ? (short)(object)left > (short)(object)right - : typeof(T) == typeof(uint) - ? (uint)(object)left > (uint)(object)right - : typeof(T) == typeof(int) - ? (int)(object)left > (int)(object)right - : typeof(T) == typeof(ulong) - ? (ulong)(object)left > (ulong)(object)right - : typeof(T) == typeof(long) - ? (long)(object)left > (long)(object)right - : typeof(T) == typeof(nuint) - ? (nuint)(object)left > (nuint)(object)right - : typeof(T) == typeof(nint) - ? (nint)(object)left > (nint)(object)right - : typeof(T) == typeof(float) - ? (float)(object)left > (float)(object)right - : typeof(T) == typeof(double) - ? (double)(object)left > (double)(object)right + => typeof(T) == typeof(byte) ? (byte)(object)left > (byte)(object)right + : typeof(T) == typeof(sbyte) ? (sbyte)(object)left > (sbyte)(object)right + : typeof(T) == typeof(ushort) ? (ushort)(object)left > (ushort)(object)right + : typeof(T) == typeof(short) ? (short)(object)left > (short)(object)right + : typeof(T) == typeof(uint) ? (uint)(object)left > (uint)(object)right + : typeof(T) == typeof(int) ? (int)(object)left > (int)(object)right + : typeof(T) == typeof(ulong) ? (ulong)(object)left > (ulong)(object)right + : typeof(T) == typeof(long) ? (long)(object)left > (long)(object)right + : typeof(T) == typeof(nuint) ? (nuint)(object)left > (nuint)(object)right + : typeof(T) == typeof(nint) ? (nint)(object)left > (nint)(object)right + : typeof(T) == typeof(float) ? (float)(object)left > (float)(object)right + : typeof(T) == typeof(double) ? (double)(object)left > (double)(object)right : left.CompareTo(right) > 0; } @@ -525,8 +489,9 @@ internal sealed class ArraySortHelper : IArraySortHelper CreateArraySortHelper() => typeof(IComparable).IsAssignableFrom(typeof(TKey)) - ? (IArraySortHelper)Activator.CreateInstance(typeof(GenericArraySortHelper<,>).MakeGenericType(typeof(TKey), typeof(TValue))) - : new ArraySortHelper(); + ? (IArraySortHelper)Activator.CreateInstance( + typeof(GenericArraySortHelper<,>).MakeGenericType(typeof(TKey), typeof(TValue))) + : new ArraySortHelper(); public void Sort(Span keys, Span values, IComparer? comparer) { @@ -546,19 +511,20 @@ internal sealed class ArraySortHelper : IArraySortHelper keys, Span values, IComparer comparer, int i, int j) + private static void SwapIfGreaterWithValues(Span keys, Span values, IComparer comparer, int i, + int j) { Debug.Assert(comparer != null); Debug.Assert(0 <= i && i < keys.Length && i < values.Length); Debug.Assert(0 <= j && j < keys.Length && j < values.Length); Debug.Assert(i != j); - if (comparer!.Compare(keys[i], keys[j]) > 0) - { - (keys[j], keys[i]) = (keys[i], keys[j]); + if (comparer!.Compare(keys[i], keys[j]) <= 0) + return; - (values[j], values[i]) = (values[i], values[j]); - } + (keys[j], keys[i]) = (keys[i], keys[j]); + + (values[j], values[i]) = (values[i], values[j]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -577,9 +543,7 @@ internal sealed class ArraySortHelper : IArraySortHelper 1) - { IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer!); - } } public static void IntroSort(Span keys, Span values, int depthLimit, IComparer comparer) @@ -594,7 +558,6 @@ internal sealed class ArraySortHelper : IArraySortHelper : IArraySortHelper : IArraySortHelper : IArraySortHelper : IArraySortHelper> 1; i >= 1; i--) - { DownHeap(keys, values, i, n, comparer!); - } for (var i = n; i > 1; i--) { @@ -697,9 +659,7 @@ internal sealed class ArraySortHelper : IArraySortHelper : IArraySortHelper : IArraySortHelper.IntrospectiveSort(keys, values, comparer); - } } catch (IndexOutOfRangeException) { @@ -818,7 +774,6 @@ internal sealed class GenericArraySortHelper : IArraySortHelper : IArraySortHelper : IArraySortHelper 0 && keys[--right] != null) ; @@ -895,9 +853,7 @@ internal sealed class GenericArraySortHelper : IArraySortHelper : IArraySortHelper> 1; i >= 1; i--) - { DownHeap(keys, values, i, n); - } for (var i = n; i > 1; i--) { @@ -927,9 +881,7 @@ internal sealed class GenericArraySortHelper : IArraySortHelper : IArraySortHelper typeof(TKey) == typeof(byte) - ? (byte)(object)left < (byte)(object)right - : typeof(TKey) == typeof(sbyte) - ? (sbyte)(object)left < (sbyte)(object)right - : typeof(TKey) == typeof(ushort) - ? (ushort)(object)left < (ushort)(object)right - : typeof(TKey) == typeof(short) - ? (short)(object)left < (short)(object)right - : typeof(TKey) == typeof(uint) - ? (uint)(object)left < (uint)(object)right - : typeof(TKey) == typeof(int) - ? (int)(object)left < (int)(object)right - : typeof(TKey) == typeof(ulong) - ? (ulong)(object)left < (ulong)(object)right - : typeof(TKey) == typeof(long) - ? (long)(object)left < (long)(object)right - : typeof(TKey) == typeof(nuint) - ? (nuint)(object)left < (nuint)(object)right - : typeof(TKey) == typeof(nint) - ? (nint)(object)left < (nint)(object)right - : typeof(TKey) == typeof(float) - ? (float)(object)left < (float)(object)right - : typeof(TKey) == typeof(double) - ? (double)(object)left < (double)(object)right + => typeof(TKey) == typeof(byte) ? (byte)(object)left < (byte)(object)right + : typeof(TKey) == typeof(sbyte) ? (sbyte)(object)left < (sbyte)(object)right + : typeof(TKey) == typeof(ushort) ? (ushort)(object)left < (ushort)(object)right + : typeof(TKey) == typeof(short) ? (short)(object)left < (short)(object)right + : typeof(TKey) == typeof(uint) ? (uint)(object)left < (uint)(object)right + : typeof(TKey) == typeof(int) ? (int)(object)left < (int)(object)right + : typeof(TKey) == typeof(ulong) ? (ulong)(object)left < (ulong)(object)right + : typeof(TKey) == typeof(long) ? (long)(object)left < (long)(object)right + : typeof(TKey) == typeof(nuint) ? (nuint)(object)left < (nuint)(object)right + : typeof(TKey) == typeof(nint) ? (nint)(object)left < (nint)(object)right + : typeof(TKey) == typeof(float) ? (float)(object)left < (float)(object)right + : typeof(TKey) == typeof(double) ? (double)(object)left < (double)(object)right : left.CompareTo(right) < 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call private static bool GreaterThan(ref TKey left, ref TKey right) - => typeof(TKey) == typeof(byte) - ? (byte)(object)left > (byte)(object)right - : typeof(TKey) == typeof(sbyte) - ? (sbyte)(object)left > (sbyte)(object)right - : typeof(TKey) == typeof(ushort) - ? (ushort)(object)left > (ushort)(object)right - : typeof(TKey) == typeof(short) - ? (short)(object)left > (short)(object)right - : typeof(TKey) == typeof(uint) - ? (uint)(object)left > (uint)(object)right - : typeof(TKey) == typeof(int) - ? (int)(object)left > (int)(object)right - : typeof(TKey) == typeof(ulong) - ? (ulong)(object)left > (ulong)(object)right - : typeof(TKey) == typeof(long) - ? (long)(object)left > (long)(object)right - : typeof(TKey) == typeof(nuint) - ? (nuint)(object)left > (nuint)(object)right - : typeof(TKey) == typeof(nint) - ? (nint)(object)left > (nint)(object)right - : typeof(TKey) == typeof(float) - ? (float)(object)left > (float)(object)right - : typeof(TKey) == typeof(double) - ? (double)(object)left > (double)(object)right + => typeof(TKey) == typeof(byte) ? (byte)(object)left > (byte)(object)right + : typeof(TKey) == typeof(sbyte) ? (sbyte)(object)left > (sbyte)(object)right + : typeof(TKey) == typeof(ushort) ? (ushort)(object)left > (ushort)(object)right + : typeof(TKey) == typeof(short) ? (short)(object)left > (short)(object)right + : typeof(TKey) == typeof(uint) ? (uint)(object)left > (uint)(object)right + : typeof(TKey) == typeof(int) ? (int)(object)left > (int)(object)right + : typeof(TKey) == typeof(ulong) ? (ulong)(object)left > (ulong)(object)right + : typeof(TKey) == typeof(long) ? (long)(object)left > (long)(object)right + : typeof(TKey) == typeof(nuint) ? (nuint)(object)left > (nuint)(object)right + : typeof(TKey) == typeof(nint) ? (nint)(object)left > (nint)(object)right + : typeof(TKey) == typeof(float) ? (float)(object)left > (float)(object)right + : typeof(TKey) == typeof(double) ? (double)(object)left > (double)(object)right : left.CompareTo(right) > 0; } @@ -1041,15 +969,13 @@ internal static class SortUtils for (var i = 0; i < keys.Length; i++) { - if ((typeof(TKey) == typeof(double) && double.IsNaN((double)(object)keys[i])) || - (typeof(TKey) == typeof(float) && float.IsNaN((float)(object)keys[i]))) + if ((typeof(TKey) == typeof(double) && double.IsNaN((double)(object)keys[i])) + || (typeof(TKey) == typeof(float) && float.IsNaN((float)(object)keys[i]))) { (keys[i], keys[left]) = (keys[left], keys[i]); if ((uint)i < (uint)values.Length) // check to see if we have values - { (values[i], values[left]) = (values[left], values[i]); - } left++; } @@ -1067,9 +993,12 @@ internal static class SortUtils internal static void ThrowArgumentException_BadComparer(object? comparer) => throw new ArgumentException(string.Format(Arg_BogusIComparer, comparer)); - internal static string InvalidOperation_IComparerFailed => "Failed to compare two elements in the array."; + internal static string InvalidOperation_IComparerFailed = "Failed to compare two elements in the array."; + internal static string Arg_BogusIComparer - => "Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: '{0}'."; + = "Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not " + + "compare equal to itself, or one value repeatedly compared to another value yields different results. " + + "IComparer: '{0}'."; } internal interface IArraySortHelper @@ -1085,12 +1014,40 @@ internal interface IArraySortHelper internal static class BitOperations { private static ReadOnlySpan Log2DeBruijn - => new byte[32] + => new byte[] { - 00, 09, 01, 10, 13, 21, 02, 29, - 11, 14, 16, 18, 22, 25, 03, 30, - 08, 12, 20, 28, 15, 17, 24, 07, - 19, 27, 23, 06, 26, 05, 04, 31 + 00, + 09, + 01, + 10, + 13, + 21, + 02, + 29, + 11, + 14, + 16, + 18, + 22, + 25, + 03, + 30, + 08, + 12, + 20, + 28, + 15, + 17, + 24, + 07, + 19, + 27, + 23, + 06, + 26, + 05, + 04, + 31 }; /// @@ -1160,4 +1117,5 @@ internal static class BitOperations // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here (IntPtr)(int)((value * 0x07C4ACDDu) >> 27)); } -} \ No newline at end of file +} +#pragma warning restore CS8500 \ No newline at end of file diff --git a/Source/FisheryLib/BoolExtensions.cs b/Source/FisheryLib/BoolExtensions.cs index 5942908..b25c288 100644 --- a/Source/FisheryLib/BoolExtensions.cs +++ b/Source/FisheryLib/BoolExtensions.cs @@ -5,12 +5,14 @@ // https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Extensions/BoolExtensions.cs using System.Runtime.CompilerServices; +using JetBrains.Annotations; namespace FisheryLib; /// /// Helpers for working with the type. /// +[PublicAPI] public static class BoolExtensions { /// @@ -27,7 +29,7 @@ public static class BoolExtensions // remove unwanted stack spills if the caller is using constant arguments. This is // because taking the address of an argument can interfere with some of the flow // analysis executed by the JIT, which can in some cases block constant propagation. - bool copy = flag; + var copy = flag; return *(byte*)© } @@ -49,10 +51,10 @@ public static class BoolExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe int ToBitwiseMask32(this bool flag) { - bool copy = flag; - byte rangeFlag = *(byte*)© - int negativeFlag = rangeFlag - 1; - int mask = ~negativeFlag; + var copy = flag; + var rangeFlag = *(byte*)© + var negativeFlag = rangeFlag - 1; + var mask = ~negativeFlag; return mask; } @@ -67,10 +69,10 @@ public static class BoolExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe long ToBitwiseMask64(this bool flag) { - bool copy = flag; - byte rangeFlag = *(byte*)© - long negativeFlag = (long)rangeFlag - 1; - long mask = ~negativeFlag; + var copy = flag; + var rangeFlag = *(byte*)© + var negativeFlag = (long)rangeFlag - 1; + var mask = ~negativeFlag; return mask; } diff --git a/Source/FisheryLib/Cecil/CecilExtensions.cs b/Source/FisheryLib/Cecil/CecilExtensions.cs new file mode 100644 index 0000000..2b2f4eb --- /dev/null +++ b/Source/FisheryLib/Cecil/CecilExtensions.cs @@ -0,0 +1,559 @@ +// Copyright (c) 2023 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System.Runtime.CompilerServices; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Collections.Generic; +using Verse; +using CallSite = Mono.Cecil.CallSite; + +namespace FisheryLib.Cecil; + +public static class CecilExtensions +{ + public static MethodReference ImportReference(this ModuleDefinition module, Delegate method) + => module.ImportReference(method.Method); + + public static MethodReference MakeGenericMethod(this MethodReference genericMethodDefinition, + ICollection genericArguments) where T : TypeReference + { + if (genericArguments.Count != genericMethodDefinition.GenericParameters.Count) + ThrowForInvalidGenericArgumentCount(genericMethodDefinition, genericArguments); + + var genericInstanceMethod = new GenericInstanceMethod(genericMethodDefinition); + foreach (var genericArgument in genericArguments) + genericInstanceMethod.GenericArguments.Add(genericArgument); + + return genericInstanceMethod; + } + + private static void ThrowForInvalidGenericArgumentCount(IGenericParameterProvider genericParameterProvider, + ICollection genericArguments) where T : TypeReference + => throw new ArgumentException( + $"Invalid generic argument count for {genericParameterProvider}. Received { + genericArguments.Count}, must be {genericParameterProvider.GenericParameters.Count}"); + + public static MethodReference MakeGenericMethod(this MethodReference genericMethodDefinition, + params T[] genericArguments) where T : TypeReference + => MakeGenericMethod(genericMethodDefinition, (ICollection)genericArguments); + + public static MethodReference ImportMethodWithGenericArguments(this ModuleDefinition module, MethodInfo method, + ICollection genericArguments) where T : TypeReference + => module.ImportReference(method.IsGenericMethodDefinition ? method : method.GetGenericMethodDefinition()) + .MakeGenericMethod(genericArguments); + + public static MethodReference ImportMethodWithGenericArguments(this ModuleDefinition module, MethodInfo method, + params T[] genericArguments) where T : TypeReference + => module.ImportMethodWithGenericArguments(method, (ICollection)genericArguments); + + public static MethodReference ImportMethodWithGenericArguments(this ModuleDefinition module, Delegate method, + ICollection genericArguments) where T : TypeReference + => module.ImportMethodWithGenericArguments(method.Method, genericArguments); + + public static MethodReference ImportMethodWithGenericArguments(this ModuleDefinition module, Delegate method, + params T[] genericArguments) where T : TypeReference + => module.ImportMethodWithGenericArguments(method.Method, (ICollection)genericArguments); + + public static TypeReference MakeGenericType(this TypeReference genericTypeDefinition, + ICollection genericArguments) where T : TypeReference + { + if (genericArguments.Count != genericTypeDefinition.GenericParameters.Count) + ThrowForInvalidGenericArgumentCount(genericTypeDefinition, genericArguments); + + var genericInstanceType = new GenericInstanceType(genericTypeDefinition); + foreach (var genericArgument in genericArguments) + genericInstanceType.GenericArguments.Add(genericArgument); + + return genericInstanceType; + } + + public static TypeReference MakeGenericType(this TypeReference genericTypeDefinition, + params T[] genericArguments) where T : TypeReference + => MakeGenericType(genericTypeDefinition, (ICollection)genericArguments); + + public static TypeReference ImportTypeWithGenericArguments(this ModuleDefinition module, Type type, + ICollection genericArguments) where T : TypeReference + => module.ImportReference(type.IsGenericTypeDefinition ? type : type.GetElementType()) + .MakeGenericType(genericArguments); + + public static TypeReference ImportTypeWithGenericArguments(this ModuleDefinition module, Type type, + params T[] genericArguments) where T : TypeReference + => module.ImportTypeWithGenericArguments(type, (ICollection)genericArguments); + + public static VariableDefinition DeclareLocal(this ILProcessor ilProcessor, Type localType) + { + var variableDefinition = new VariableDefinition(ilProcessor.GetModule().ImportReference(localType)); + ilProcessor.Body.Variables.Add(variableDefinition); + return variableDefinition; + } + + public static VariableDefinition DeclareLocal(this ILProcessor ilProcessor, TypeReference localType) + { + var variableDefinition = new VariableDefinition(localType); + ilProcessor.Body.Variables.Add(variableDefinition); + return variableDefinition; + } + + public static void InsertAt(this ILProcessor ilProcessor, int index, Instruction instruction) + => ilProcessor.instructions.Insert(index, instruction); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode) + => ilProcessor.InsertAt(index, Instruction.Create(opCode)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, TypeReference type) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, type)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, Type type) + => ilProcessor.InsertAt(index, opCode, ilProcessor.GetModule().ImportReference(type)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, CallSite site) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, site)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, MethodReference method) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, method)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, MethodBase method, + params Type[] genericArguments) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, + ImportReferenceWithOptionalGenericArguments(method, ilProcessor.GetModule(), genericArguments))); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, Delegate method, + params Type[] genericArguments) + => ilProcessor.InsertAt(index, opCode, method.Method, genericArguments); + + private static MethodReference ImportReferenceWithOptionalGenericArguments(MethodBase method, + ModuleDefinition module, params Type[] genericArguments) + => genericArguments.Length > 0 + ? module.ImportMethodWithGenericArguments((MethodInfo)method, genericArguments) + : module.ImportReference(method); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, FieldReference field) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, field)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, FieldInfo field) + => ilProcessor.InsertAt(index, opCode, ilProcessor.GetModule().ImportReference(field)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, string value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, sbyte value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, byte value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, int value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, long value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, nint value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, float value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, double value) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, value)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, Instruction target) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, target)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, Instruction[] targets) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, targets)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, VariableDefinition variable) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, variable)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, ParameterDefinition parameter) + => ilProcessor.InsertAt(index, Instruction.Create(opCode, parameter)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, OpCode opCode, object operand) + => ilProcessor.InsertAt(index, CreateInstruction(opCode, operand)); + + public static void InsertAt(this ILProcessor ilProcessor, int index, object instruction) + { + var module = ilProcessor.GetModule(); + ilProcessor.InsertAt(index, instruction switch + { + Instruction codeInstruction => codeInstruction, + OpCode opCode => Instruction.Create(opCode), + ITuple tuple => CreateInstruction(tuple is [OpCode opCode, _, ..] + ? opCode + : ThrowArgumentExceptionForInvalidType(instruction), + tuple[1] switch + { + MethodBase => ImportMethodFromTuple(tuple, module), + FieldInfo fieldInfo => module.ImportReference(fieldInfo), + Type => ImportTypeFromTuple(tuple, module), + ParameterInfo parameterInfo => GetParameterDefinition(ilProcessor, parameterInfo), + Delegate @delegate => module.ImportReference(@delegate.Method), + _ => tuple[1] + }), + _ => ThrowArgumentExceptionForInvalidType(instruction) + }); + } + + private static ParameterDefinition GetParameterDefinition(ILProcessor ilProcessor, ParameterInfo parameterInfo) + { + var parameters = ilProcessor.Body.Method.Parameters; + foreach (var parameter in parameters) + { + if (parameter.Name == parameterInfo.Name) + return parameter; + } + + return ThrowHelper.ThrowArgumentException($"Could not find parameter named { + parameterInfo.Name} in method {ilProcessor.Body.Method.FullName}"); + } + + private static MethodReference ImportMethodFromTuple(ITuple tuple, ModuleDefinition module) + { + var tupleLength = tuple.Length; + Guard.IsGreaterThanOrEqualTo(tupleLength, 2); + + if (tupleLength == 2) + return module.ImportReference((MethodBase)tuple[1]); + + var methodInfo = (MethodInfo)tuple[1]; + switch (tuple[2]) + { + case Type[] typeArray: + { + return module.ImportMethodWithGenericArguments(methodInfo, typeArray); + } + case Type: + { + var genericArguments = new Type[tupleLength - 2]; + for (var i = 2; i < tupleLength; i++) + genericArguments[i - 2] = (Type)tuple[i]; + + return module.ImportMethodWithGenericArguments(methodInfo, genericArguments); + } + case Collection genericParameterCollection: + { + return module.ImportMethodWithGenericArguments(methodInfo, genericParameterCollection); + } + case Collection typeReferenceCollection: + { + return module.ImportMethodWithGenericArguments(methodInfo, typeReferenceCollection); + } + case TypeReference: + { + var genericArguments = new TypeReference[tupleLength - 2]; + for (var i = 2; i < tupleLength; i++) + genericArguments[i - 2] = (TypeReference)tuple[i]; + + return module.ImportMethodWithGenericArguments(methodInfo, genericArguments); + } + default: + { + return ThrowHelper.ThrowArgumentException( + $"Tuple contains invalid type: {tuple[2].GetType().FullName}"); + } + } + } + + private static TypeReference ImportTypeFromTuple(ITuple tuple, ModuleDefinition module) + { + var tupleLength = tuple.Length; + Guard.IsGreaterThanOrEqualTo(tupleLength, 2); + + if (tupleLength == 2) + return module.ImportReference((Type)tuple[1]); + + var type = (Type)tuple[1]; + switch (tuple[2]) + { + case Type[] typeArray: + { + return module.ImportTypeWithGenericArguments(type, typeArray); + } + case Type: + { + var genericArguments = new Type[tupleLength - 2]; + for (var i = 2; i < tupleLength; i++) + genericArguments[i - 2] = (Type)tuple[i]; + + return module.ImportTypeWithGenericArguments(type, genericArguments); + } + case Collection genericParameterCollection: + { + return module.ImportTypeWithGenericArguments(type, genericParameterCollection); + } + case Collection typeReferenceCollection: + { + return module.ImportTypeWithGenericArguments(type, typeReferenceCollection); + } + case TypeReference: + { + var genericArguments = new TypeReference[tupleLength - 2]; + for (var i = 2; i < tupleLength; i++) + genericArguments[i - 2] = (TypeReference)tuple[i]; + + return module.ImportTypeWithGenericArguments(type, genericArguments); + } + default: + { + return ThrowHelper.ThrowArgumentException( + $"Tuple contains invalid type: {tuple[2].GetType().FullName}"); + } + } + } + + public static void InsertRange(this ILProcessor ilProcessor, int index, IEnumerable instructions) + { + foreach (var instruction in instructions) + ilProcessor.InsertAt(index++, instruction); + } + + public static void InsertRange(this ILProcessor ilProcessor, int index, params Instruction[] instructions) + { + for (var i = 0; i < instructions.Length; i++) + ilProcessor.InsertAt(index++, instructions[i]); + } + + public static void InsertRange(this ILProcessor ilProcessor, int index, IEnumerable instructions) + { + foreach (var instruction in instructions) + ilProcessor.InsertAt(index++, instruction); + } + + public static void InsertRange(this ILProcessor ilProcessor, int index, params object[] instructions) + { + for (var i = 0; i < instructions.Length; i++) + ilProcessor.InsertAt(index++, instructions[i]); + } + + public static void ReplaceBodyWith(this ILProcessor ilProcessor, Delegate replacement) + => ilProcessor.ReplaceBodyWith(replacement.Method); + + public static void ReplaceBodyWith(this ILProcessor ilProcessor, MethodInfo replacement) + { + var oldBody = ilProcessor.Body; + var module = oldBody.Method.Module; + + if (replacement.IsGenericMethod) + replacement = replacement.GetGenericMethodDefinition(); + + if (replacement.DeclaringType!.IsGenericType) + { + replacement = AccessTools.DeclaredMethod(replacement.DeclaringType.GetGenericTypeDefinition(), + replacement.Name, replacement.GetParameters().GetTypes()); + } + + var newMethodReference = module.ImportReference(replacement); + var newBody = newMethodReference.Resolve().Body; + + oldBody.Instructions.Clear(); + foreach (var instruction in newBody.instructions) + { + oldBody.Instructions.Add(new(instruction.OpCode, instruction.Operand switch + { + FieldReference field => module.ImportReference(field, newMethodReference), + MethodReference method => module.ImportReference(method, newMethodReference), + TypeReference type => module.ImportReference(type, newMethodReference), + _ => instruction.Operand + })); + } + + oldBody.Variables.Clear(); + foreach (var variable in newBody.Variables) + oldBody.Variables.Add(new(module.ImportReference(variable.VariableType, newMethodReference))); + + oldBody.MaxStackSize = newBody.MaxStackSize; + + oldBody.ExceptionHandlers.Clear(); + foreach (var exceptionHandler in newBody.ExceptionHandlers) + { + var handler = new ExceptionHandler(exceptionHandler.HandlerType) + { + TryStart = exceptionHandler.TryStart, + TryEnd = exceptionHandler.TryEnd, + FilterStart = exceptionHandler.FilterStart, + HandlerStart = exceptionHandler.HandlerStart, + HandlerEnd = exceptionHandler.HandlerEnd + }; + + if (exceptionHandler.CatchType is { } catchType) + handler.CatchType = module.ImportReference(catchType, newMethodReference); + + oldBody.ExceptionHandlers.Add(handler); + } + + oldBody.Method.ImplAttributes = newBody.Method.ImplAttributes; + } + + public static MethodDefinition GetMethod(this ILProcessor ilProcessor) => ilProcessor.Body.Method; + + public static MethodDefinition? GetMethod(this TypeDefinition type, string name, Type?[]? parameters = null) + { + var methods = type.Methods; + MethodDefinition? foundMethod = null; + + for (var i = 0; i < methods.Count; i++) + { + var method = methods[i]; + if (method.Name != name + || !TestForMatchingTypes(parameters, method.Parameters, static p => p.ParameterType.Name)) + { + continue; + } + + if (foundMethod != null) + ThrowForAmbiguousMatch(type, name, parameters); + else + foundMethod = method; + } + + return foundMethod; + } + + public static TypeDefinition? GetTypeDefinition(this ModuleDefinition module, Type type) + => type.DeclaringType is { } declaringType + ? module.GetTypeDefinition(declaringType)?.NestedTypes.GetNamed(type.Name) + : module.GetType(type.Namespace, type.Name); + + private static void ThrowForAmbiguousMatch(TypeDefinition type, string name, Type?[]? parameters) + => throw new AmbiguousMatchException($"Ambiguous match found for type: {type.FullName}, name: { + name}, parameters: {parameters.ToStringSafeEnumerable()}"); + + private static bool TestForMatchingTypes(Type?[]? types, Collection? testedTypes, + Func typeNameGetter) + { + if (types is null) + return true; + + if (testedTypes is null || testedTypes.Count != types.Length) + return false; + + var typesNotMatching = false; + for (var i = 0; i < types.Length; i++) + { + var type = types[i]; + if (type is null || type.IsGenericParameter) + continue; + + if (typeNameGetter(testedTypes[i]) != type.Name) + typesNotMatching = true; + } + + return !typesNotMatching; + } + + public static ModuleDefinition GetModule(this ILProcessor ilProcessor) => ilProcessor.GetMethod().Module; + + public static Collection? TryGetGenericArguments(this MethodReference method) + => method is GenericInstanceMethod instanceMethod + ? instanceMethod.GenericArguments + : method.DeclaringType.TryGetGenericArguments(); + + public static Collection? TryGetGenericArguments(this TypeReference type) + { + while (type != null) + { + if (type is GenericInstanceType instanceType) + return instanceType.GenericArguments; + + type = type.DeclaringType; + } + + return null; + } + + public static Collection? TryGetGenericArguments(this TypeReference type, + IGenericParameterProvider provider) + { + while (type != null) + { + if (type is GenericInstanceType instanceType) + return instanceType.GenericArguments.ConvertAll(g => g.TryGetGenericParameterType(provider) ?? g); + + type = type.DeclaringType; + } + + return null; + } + + public static Collection? TryGetGenericArguments(this IGenericParameterProvider provider) + => provider switch + { + null => ThrowHelper.ThrowArgumentNullException>(nameof(provider)), + MethodReference method => method.TryGetGenericArguments(), + TypeReference type => type.TryGetGenericArguments(), + _ => ThrowHelper.ThrowArgumentException>( + $"Generic parameter provider has unsupported type: {provider.GetType()}") + }; + + public static TypeReference? TryGetGenericParameterType(this TypeReference typeReference, + IGenericParameterProvider provider) + => typeReference is GenericParameter genericParameter + ? TryGetUnderlyingType(genericParameter, provider) + : null; + + public static TypeReference? TryGetUnderlyingType(GenericParameter genericParameter, + IGenericParameterProvider provider) + => (genericParameter.Owner is TypeReference ownerType && provider is MemberReference providerMember + ? providerMember.TryGetParentOfName(ownerType.Name) + : provider)?.TryGetGenericArguments()?[genericParameter.Position]; + + + public static Collection ConvertAll(this Collection collection, + Converter converter) + { + var result = new Collection(collection.Count); + + for (var i = 0; i < collection.Count; i++) + result.Add(converter(collection[i])); // somehow throws OutOfRangeExceptions when using set_Item here + // Storing collection.Count in a var makes no difference + + return result; + } + + private static TypeReference? TryGetParentOfName(this MemberReference providerMember, string name) + { + var type = providerMember as TypeReference ?? providerMember.DeclaringType; + while (type != null) + { + if (type.Name == name) + return type; + + type = type.DeclaringType; + } + + return null; + } + + private static T ThrowArgumentExceptionForInvalidType(object instruction) + => ThrowHelper.ThrowArgumentException(nameof(instruction), + // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract + $"Argument is of invalid type: {instruction?.GetType().FullName ?? "NULL"}"); + + private static Instruction CreateInstruction(OpCode opCode, object operand) + => operand switch + { + TypeReference type => Instruction.Create(opCode, type), + CallSite site => Instruction.Create(opCode, site), + MethodReference method => Instruction.Create(opCode, method), + FieldReference field => Instruction.Create(opCode, field), + string value => Instruction.Create(opCode, value), + sbyte value => Instruction.Create(opCode, value), + byte value => Instruction.Create(opCode, value), + int value => Instruction.Create(opCode, value), + long value => Instruction.Create(opCode, value), + float value => Instruction.Create(opCode, value), + double value => Instruction.Create(opCode, value), + nint value => Instruction.Create(opCode, value), + Instruction target => Instruction.Create(opCode, target), + Instruction[] targets => Instruction.Create(opCode, targets), + VariableDefinition variable => Instruction.Create(opCode, variable), + ParameterDefinition parameter => Instruction.Create(opCode, parameter), + _ => ThrowHelper.ThrowArgumentException(nameof(operand), + // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract + $"Operand for OpCode {opCode} is of invalid type: {operand?.GetType().FullName ?? "NULL"}") + }; +} \ No newline at end of file diff --git a/Source/FisheryLib/Cecil/CecilReflectionExtensions.cs b/Source/FisheryLib/Cecil/CecilReflectionExtensions.cs new file mode 100644 index 0000000..6171a9c --- /dev/null +++ b/Source/FisheryLib/Cecil/CecilReflectionExtensions.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2022 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v.2.0.If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using Mono.Cecil; + +namespace FisheryLib.Cecil; + +public static class CecilReflectionExtensions +{ + public static MethodReference ImportMethodWithGenericArguments(this ModuleDefinition module, MethodInfo method, + params Type[] genericArguments) + => module.ImportReference(method.IsGenericMethodDefinition ? method : method.GetGenericMethodDefinition()) + .MakeGenericMethod(genericArguments.GetTypeReferences(module)); + + public static MethodReference ImportMethodWithGenericArguments(this ModuleDefinition module, Delegate method, + params Type[] genericArguments) + => module.ImportMethodWithGenericArguments(method.Method, genericArguments); + + public static TypeReference ImportTypeWithGenericArguments(this ModuleDefinition module, Type type, + params Type[] genericArguments) + => module.ImportReference(type.IsGenericTypeDefinition ? type : type.GetElementType()) + .MakeGenericType(genericArguments.GetTypeReferences(module)); +} \ No newline at end of file diff --git a/Source/FisheryLib/Cecil/ReflectionExtensions.cs b/Source/FisheryLib/Cecil/ReflectionExtensions.cs new file mode 100644 index 0000000..ab83ad7 --- /dev/null +++ b/Source/FisheryLib/Cecil/ReflectionExtensions.cs @@ -0,0 +1,84 @@ +// Copyright (c) 2023 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System.Diagnostics.CodeAnalysis; +using JetBrains.Annotations; +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace FisheryLib.Cecil; + +[PublicAPI] +public static class ReflectionExtensions +{ + public static Type[] GetTypes(this ParameterInfo[] parameterInfos) + => Array.ConvertAll(parameterInfos, static p => p.ParameterType); + + public static ParameterInfo? TryGetNamed(this ParameterInfo[] parameterInfos, string name) + => TryGetNamed(parameterInfos, name, static p => p.Name); + + public static T? TryGetNamed(this T[] memberInfos, string name) where T : MemberInfo + => TryGetNamed(memberInfos, name, static m => m.Name); + + public static ParameterDefinition? TryGetNamed(this Collection parameterDefinitions, + string name) + => TryGetNamed(parameterDefinitions, name, static p => p.Name); + + public static T? TryGetNamed(this Collection memberReferences, string name) where T : MemberReference + => TryGetNamed(memberReferences, name, static m => m.Name); + + public static ParameterInfo GetNamed(this ParameterInfo[] parameterInfos, string name) + => TryGetNamed(parameterInfos, name, static p => p.Name) + ?? ThrowForMissingParameter(name); + + public static T GetNamed(this T[] memberInfos, string name) where T : MemberInfo + => TryGetNamed(memberInfos, name, static m => m.Name) + ?? ThrowForMissingMember(name); + + public static ParameterDefinition GetNamed(this Collection parameterDefinitions, + string name) + => TryGetNamed(parameterDefinitions, name, static p => p.Name) + ?? ThrowForMissingParameter(name); + + public static T GetNamed(this Collection memberReferences, string name) where T : MemberReference + => TryGetNamed(memberReferences, name, static m => m.Name) + ?? ThrowForMissingMember(name); + + [DoesNotReturn] + private static T ThrowForMissingMember(string name) + => ThrowHelper.ThrowInvalidOperationException($"Sequence contains no member with name: {name}"); + + [DoesNotReturn] + private static T ThrowForMissingParameter(string name) + => ThrowHelper.ThrowInvalidOperationException( + $"Sequence contains no parameter with name: {name}"); + + private static T? TryGetNamed(this IList memberInfos, string name, Func nameGetter) + where T : class + { + for (var i = 0; i < memberInfos.Count; i++) + { + if (nameGetter(memberInfos[i]) == name) + return memberInfos[i]; + } + + return null; + } + + public static TypeReference[] GetTypeReferences(this Type[] types, ModuleDefinition module) + { + var result = new TypeReference[types.Length]; + for (var i = types.Length; i-- > 0;) + result[i] = module.ImportReference(types[i]); + + return result; + } + + public static bool IsGeneric(this TypeReference type) + => type.ContainsGenericParameter || type.HasGenericParameters || type.IsGenericInstance; + + public static bool IsGeneric(this Type type) + => type.ContainsGenericParameters || type.IsGenericType || type.IsConstructedGenericType; +} \ No newline at end of file diff --git a/Source/FisheryLib/CollectionExtensions.cs b/Source/FisheryLib/CollectionExtensions.cs index 136f7de..c612a65 100644 --- a/Source/FisheryLib/CollectionExtensions.cs +++ b/Source/FisheryLib/CollectionExtensions.cs @@ -7,15 +7,20 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; +using FisheryLib.Collections; +using JetBrains.Annotations; namespace FisheryLib; + +[PublicAPI] public static class CollectionExtensions { public static bool TryGetItem(this List list, int index, [NotNullWhen(true)] out T? item) { - if (list.Count > index) + if (list._size > index) { - item = list[index]!; + item = list._items[index]!; return true; } @@ -24,19 +29,23 @@ public static class CollectionExtensions } /// - /// Taken from Span<>.this[] and slower than List<>.this[] due to the ArrayAdjustment + /// Taken from Span.this[] and slower than List.this[] due to the ArrayAdjustment /// internal static T GetItemUnchecked(this List list, int index) - => Unsafe.Add(ref Unsafe.AddByteOffset(ref Unsafe.As>(list._items).Data, PerTypeValues.ArrayAdjustment), index)!; + => Unsafe.Add( + ref Unsafe.AddByteOffset(ref Unsafe.As>(list._items).Data, PerTypeValues.ArrayAdjustment), + index)!; [StructLayout(LayoutKind.Sequential)] private sealed class Pinnable { public T? Data; } + private static class PerTypeValues { public static readonly IntPtr ArrayAdjustment = MeasureArrayAdjustment(); + private static IntPtr MeasureArrayAdjustment() { var array = new T[1]; @@ -60,8 +69,8 @@ public static class CollectionExtensions { var array = new T[length]; - if (enumerable is IList ilist) - array.Fill(ilist); + if (enumerable is IList iList) + array.Fill(iList); else array.FillUsingEnumerable(enumerable); @@ -81,15 +90,16 @@ public static class CollectionExtensions { Guard.IsNotNull(destination); - if (enumerable is IList ilist) - destination.Fill(ilist); + if (enumerable is IList iList) + destination.Fill(iList); else destination.FillUsingEnumerable(enumerable); return destination; } - private static void FillUsingEnumerable(this T[] array, IEnumerable enumerable, int startIndex = 0, int count = -1) + private static void FillUsingEnumerable(this T[] array, IEnumerable enumerable, int startIndex = 0, + int count = -1) { var i = 0u; foreach (var item in enumerable) @@ -102,7 +112,8 @@ public static class CollectionExtensions } } - public static void Fill(this Telement[] array, Tcollection collection, int startIndex = 0, int count = -1) + public static void Fill(this Telement[] array, Tcollection collection, int startIndex = 0, + int count = -1) where Tcollection : IList { Guard.IsNotNull(collection); @@ -124,8 +135,8 @@ public static class CollectionExtensions { Guard.IsNotNull(enumerable); - if (enumerable is IList ilist) - array.Fill(ilist, startIndex, count); + if (enumerable is IList iList) + array.Fill(iList, startIndex, count); else array.FillUsingEnumerable(enumerable, startIndex, count); } @@ -146,6 +157,27 @@ public static class CollectionExtensions bucket = entry.next; } } + + return ref ThrowKeyNotFoundException(key); + } + + public static ref TValue GetReference(this Dictionary dictionary, ref TKey key) + { + if (dictionary.buckets != null) + { + var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF; + + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key)) + return ref entry.value; + + bucket = entry.next; + } + } + return ref ThrowKeyNotFoundException(key); } @@ -153,6 +185,7 @@ public static class CollectionExtensions /// Returns a reference to the value field of an entry if the key exists and an Unsafe.NullRef{TValue} if not. /// Must be checked with Unsafe.IsNullRef before assigning to a regular var or field without ref. /// + /// The instance /// The key /// ref TValue or Unsafe.NullRef{TValue} public static ref TValue TryGetReferenceUnsafe(this Dictionary dictionary, TKey key) @@ -171,11 +204,11 @@ public static class CollectionExtensions bucket = entry.next; } } + return ref Unsafe.NullRef(); } public static ref TValue TryGetReferenceUnsafe(this Dictionary dictionary, ref TKey key) - where TKey : struct { if (dictionary.buckets != null) { @@ -185,12 +218,13 @@ public static class CollectionExtensions while (bucket >= 0) { ref var entry = ref dictionary.entries[bucket]; - if (entry.hashCode == keyCode && entry.key.Equals(ref key)) + if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key)) return ref entry.value; bucket = entry.next; } } + return ref Unsafe.NullRef(); } @@ -210,6 +244,7 @@ public static class CollectionExtensions bucket = entry.next; } } + return default; } @@ -230,8 +265,161 @@ public static class CollectionExtensions bucket = entry.next; } } + return default; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TValue GetOrAddReference(this Dictionary dictionary, TKey key) + where TValue : new() + { + var keyCode = HashCode.Get(key) & 0x7FFFFFFF; + + StartOfLookup: + if (dictionary.buckets != null) + { + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && entry.key.Equals(key)) + return ref entry.value; + + bucket = entry.next; + } + } + + dictionary.Add(key, Reflection.New()); + goto StartOfLookup; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TValue GetOrAddReference(this Dictionary dictionary, ref TKey key) + where TValue : new() + { + var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF; + + StartOfLookup: + if (dictionary.buckets != null) + { + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key)) + return ref entry.value; + + bucket = entry.next; + } + } + + dictionary.Add(key, Reflection.New()); + goto StartOfLookup; + } + + // public static bool TryGetOrAddReference(this Dictionary dictionary, TKey key, + // ref TValue reference) + // { + // var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF; + // var result = true; + // + // StartOfLookup: + // if (dictionary.buckets != null) + // { + // var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + // while (bucket >= 0) + // { + // ref var entry = ref dictionary.entries[bucket]; + // if (entry.hashCode == keyCode && entry.key.Equals(key)) + // { + // reference.Value = ref entry.value; + // return result; + // } + // + // bucket = entry.next; + // } + // } + // + // result = false; + // dictionary.Add(key, Reflection.New()); + // goto StartOfLookup; + // } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TValue GetOrAdd(this Dictionary dictionary, TKey key) + where TValue : new() + { + var keyCode = HashCode.Get(key) & 0x7FFFFFFF; + + StartOfLookup: + if (dictionary.buckets != null) + { + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && entry.key.Equals(key)) + return entry.value; + + bucket = entry.next; + } + } + + dictionary.Add(key, Reflection.New()); + goto StartOfLookup; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TValue GetOrAdd(this Dictionary dictionary, ref TKey key) + where TValue : new() + { + var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF; + + StartOfLookup: + if (dictionary.buckets != null) + { + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key)) + return entry.value; + + bucket = entry.next; + } + } + + dictionary.Add(key, Reflection.New()); + goto StartOfLookup; + } + + public static bool TryGetOrAddValue(this Dictionary dictionary, TKey key, + out TValue value) + { + var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF; + var result = true; + + StartOfLookup: + if (dictionary.buckets != null) + { + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && entry.key.Equals(key)) + { + value = entry.value; + return result; + } + + bucket = entry.next; + } + } + + result = false; + dictionary.Add(key, Reflection.New()); + goto StartOfLookup; + } [DoesNotReturn] private static ref V ThrowKeyNotFoundException(T key) @@ -243,42 +431,106 @@ public static class CollectionExtensions [DoesNotReturn] private static void ThrowKeyNotFoundException(object key) - => throw new KeyNotFoundException( - string.Format("The given key '{0}' was not present in the dictionary.", key)); + => throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary."); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref int Version(this List list) => ref list._version; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void AddRangeFast(this List list, List range) + { + if (range._size < 1) + return; + + list.EnsureCapacity(list._size + range._size); + + range.UnsafeCopyTo(list, list._size); + + list._size += range._size; + list._version++; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void UnsafeCopyTo(this List source, List destination, int destinationStartIndex) + => UnsafeBlockCopy(ref source._items[0], ref destination._items[destinationStartIndex], source._size); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void UnsafeCopyTo(this T[] source, T[] destination, int destinationStartIndex) + => UnsafeBlockCopy(ref source[0], ref destination[destinationStartIndex], source.Length); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void UnsafeBlockCopy(ref T source, ref T destination, int count) + => Unsafe.CopyBlock(ref Unsafe.As(ref destination), + ref Unsafe.As(ref source), + (uint)((nint)sizeof(T) * count)); /// - /// Returns a list's internal _items array. Keep in mind list.Version() needs to change every time items are modified. + /// Returns a list's internal _items array. Keep in mind list.Version() needs to change every time items are + /// modified. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] ItemsUnchecked(this List list) => list._items; /// - /// Returns a span pointing to a list's internal _items array. Keep in mind list.Version() needs to change every time items are modified. + /// Returns a span pointing to a list's internal _items array. Keep in mind list.Version() needs to change every + /// time items are modified. /// - public static Span AsSpanUnchecked(this List list) => new(list._items, 0, list.Count); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpanUnchecked(this List list) => new(list._items, 0, list._size); - public static ReadOnlySpan AsReadOnlySpan(this List list) => new(list._items, 0, list.Count); - - public static void ReplaceContentsWith(this List list, V collection) where V : ICollection + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan AsReadOnlySpan(this List list) => new(list._items, 0, list._size); + + public static void ReplaceContentsWith(this List list, [AllowNull] List collection) { if (ReferenceEquals(list, collection)) return; if (collection is null - || (collection.Count is var collectionCount - && collectionCount == 0)) + || (collection._size is var collectionCount + && collectionCount == 0)) { list.Clear(); return; } - if (collectionCount <= list.Count) + if (collectionCount <= list._size) { - if (collectionCount < list.Count) - list.RemoveRange(collectionCount, list.Count - collectionCount); + if (collectionCount < list._size) + list.RemoveRange(collectionCount, list._size - collectionCount); + + collection.UnsafeCopyTo(list, 0); + } + else + { + list._items = new T[collectionCount]; + collection.UnsafeCopyTo(list, 0); + list._size = collectionCount; + } + + list._version++; + } + + public static void ReplaceContentsWith(this List list, [AllowNull] V collection) where V : ICollection + { + if (typeof(V) == typeof(List)) + list.ReplaceContentsWith(Unsafe.As>(collection)); + + if (ReferenceEquals(list, collection)) + return; + + if (collection is null + || (collection.Count is var collectionCount + && collectionCount == 0)) + { + list.Clear(); + return; + } + + if (collectionCount <= list._size) + { + if (collectionCount < list._size) + list.RemoveRange(collectionCount, list._size - collectionCount); collection.CopyTo(list._items, 0); } else @@ -287,18 +539,176 @@ public static class CollectionExtensions collection.CopyTo(list._items, 0); list._size = collectionCount; } + list._version++; } + public static FishTable ToFishTable(this IEnumerable source, + Func keySelector) + => source.ToFishTable(keySelector, static item => item); + + public static FishTable ToFishTable(this IEnumerable source, + Func keySelector, Func valueSelector) + { + Guard.IsNotNull(source); + Guard.IsNotNull(keySelector); + Guard.IsNotNull(valueSelector); + + var capacity = 0; + if (source is ICollection iCollection) + capacity = (int)(iCollection.Count * 1.5f); + + var fishTable = new FishTable(capacity); + fishTable.AddRange(source, keySelector, valueSelector); + return fishTable; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Clear(this T[] array) => Array.Clear(array, 0, array.Length); + + // public static List Copy(this List source) + // { + // Guard.IsNotNull(source); + // + // var destination = new List(source._size); + // + // if (source._size == 0) + // return destination; + // + // // Unsafe.CopyBlock(ref Unsafe.As(ref destination._items[0]), + // // ref Unsafe.As(ref source._items[0]), (uint)sizeof(T) * (uint)source._size); + // + // FisheryLib.CollectionExtensions.UnsafeBlockCopy(ref source._items[0], // does a type check that causes issues + // ref destination._items[0], source._size); // when called from transpiled methods + // + // destination._size = source._size; + // + // return destination; + // } + + public static unsafe List Copy(this List source) + { + Guard.IsNotNull(source); + + var destination = new List(source._size); + + if (source._size == 0) + return destination; + + fixed (void* destinationPointer = &destination._items[0], sourcePointer = &source._items[0]) + Unsafe.CopyBlock(destinationPointer, sourcePointer, (uint)(source._size * sizeof(T))); + + destination._size = source._size; + + return destination; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void AddRangeFast(this List list, T[] range) + { + Guard.IsNotNull(list); + Guard.IsNotNull(range); + + if (range.Length < 1) + return; + + list.EnsureCapacity(list._size + range.Length); + range.UnsafeCopyTo(list._items, list._size); + + list._size += range.Length; + list._version++; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Add(this List list, string value) + { + Guard.IsNotNull(list); + Guard.IsNotNull(value); + + if (value.Length < 1) + return; + + list.EnsureCapacity(list._size + value.Length); + UnsafeBlockCopy(ref value.m_firstChar, + ref list._items[list._size], value.Length); + + list._size += value.Length; + list._version++; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static StringBuilder Append(this StringBuilder builder, List value) + => builder.Append(value._items, 0, value._size); + + public static ref T GetReferenceUnverifiable(this List list, int index) => ref list._items[index]; + public static IList TryNew(IEnumerable enumerable, Type type) => GetListExtensionMethods(type).New(enumerable); - public static void TryAddRange(this IList list, T collection, Type type) where T : ICollection => GetListExtensionMethods(type).AddRange(list, collection); + public static void TryAddRange(this IList list, T collection, Type type) where T : ICollection + => GetListExtensionMethods(type).AddRange(list, collection); public static Array TryToArray(this IList list, Type type) => GetListExtensionMethods(type).ToArray(list); + + public static unsafe uint GetSizeEstimate(this Dictionary dictionary) + => dictionary.GetType().ComputeManagedObjectSizeEstimate() + + ((uint)sizeof(Dictionary.Entry) * (uint)(dictionary.entries?.Length ?? 0)) + + (sizeof(int) * (uint)(dictionary.buckets?.Length ?? 0)); + + internal static unsafe uint ComputeManagedObjectSizeEstimate(this Type type) + { + var objectHeader = (uint)sizeof(void*) * 2u; + ref var cachedSize = ref CachedManagedObjectSizes.GetOrAddReference(type.TypeHandle.Value); + + if (cachedSize.Size == uint.MaxValue) + UpdateCachedManagedObjectSize(type, ref cachedSize); + + return objectHeader + cachedSize.Size; + } + + private static void UpdateCachedManagedObjectSize(Type type, ref ManagedObjectSize cachedSize) + { + cachedSize.Size = 0; + var fields = type.GetFields(BindingFlags.Instance + | BindingFlags.Public + | BindingFlags.NonPublic); + + for (var i = fields.Length; i-- > 0;) + { + var fieldType = fields[i].FieldType; + if (!typeof(ValueType).IsAssignableFrom(fieldType) || fieldType == typeof(ValueType)) + // IsValueType and IsSubclassOf somehow cause StackOverflows here + cachedSize.Size += (uint)IntPtr.Size; + else if (fieldType.IsPrimitive) + cachedSize.Size += (uint)Marshal.SizeOf(fieldType); + else if (fieldType != type) + cachedSize.Size += fieldType.ComputeManagedObjectSizeEstimate(); + else + cachedSize.Size += (uint)IntPtr.Size; // fuck it + } + + var remainder = cachedSize.Size % (uint)IntPtr.Size; + if (remainder != 0u) + cachedSize.Size += (uint)IntPtr.Size - remainder; + } + + private static FishTable CachedManagedObjectSizes => _cachedManagedObjectSizes ??= new(); + + [ThreadStatic] + private static FishTable? _cachedManagedObjectSizes; + + private struct ManagedObjectSize + { + public uint Size = uint.MaxValue; + + [UsedImplicitly] + public ManagedObjectSize() + { + } + } public static GenericBase GetListExtensionMethods(Type type) => ListExtensionCache.TryGetValue(type) - ?? CreateListExtensionMethods(type); + ?? CreateListExtensionMethods(type); private static GenericBase CreateListExtensionMethods(Type type) { @@ -322,7 +732,8 @@ public static class CollectionExtensions public class Generic : GenericBase { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override void AddRange(IList list, ICollection collection) => ((List)list).AddRange((IEnumerable)collection); + public override void AddRange(IList list, ICollection collection) + => ((List)list).AddRange((IEnumerable)collection); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override Array ToArray(IList list) => ((List)list).ToArray(); diff --git a/Source/FisheryLib/Collections/FishSet.cs b/Source/FisheryLib/Collections/FishSet.cs new file mode 100644 index 0000000..ce432b3 --- /dev/null +++ b/Source/FisheryLib/Collections/FishSet.cs @@ -0,0 +1,862 @@ +// Copyright (c) 2023 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// Loosely based on https://github.com/matthewcrews/FastDictionaryTest/tree/main +// which itself is based on +// https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/ + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using FisheryLib.FunctionPointers; +using FisheryLib.Utility; +using JetBrains.Annotations; + +namespace FisheryLib.Collections; + +#pragma warning disable CS8766, CS8767 +[PublicAPI] +[StructLayout(LayoutKind.Sequential)] +public class FishSet : ISet, IReadOnlyCollection, ICollection +{ + private const int FIBONACCI_HASH = -1640531527; // unchecked((int)(uint)Math.Round(uint.MaxValue / FishMath.PHI)); + + internal T?[] _buckets; + + private unsafe delegate* _hashCodeGetter = GetHashCode.Default; + private unsafe delegate* _equalityComparer = Equals.Default; + + private int + _bucketBitShift, + _count; + + internal Tails _tails; + + private int + _wrapAroundMask, + _version; + + private float _maxLoadFactor = 0.5f; + + public int Version + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _version; + set + { + Guard.IsGreaterThan(value, _version); + _version = value; + } + } + + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _count; + } + + public object SyncRoot => throw new NotImplementedException(); + + public bool IsSynchronized => throw new NotImplementedException(); + + public bool IsReadOnly => false; + + public event Action? + EntryAdded, + EntryRemoved; + + public float MaxLoadFactor + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _maxLoadFactor; + set + { + Guard.IsInRange(value, 0f, 1f); + _maxLoadFactor = value; + } + } + + private static T AssertKeyType(object key) + { + if (key is T tKey) + return tKey; + else if (key != null!) + ThrowHelper.ThrowWrongKeyTypeArgumentException(key); + + return default!; + } + + public bool this[T key] + { + [CollectionAccess(CollectionAccessType.Read)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Contains(key); + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + set => InsertEntry(key, value); + } + + public FishSet() : this(0) + { + } + + public FishSet(int minimumCapacity) => Initialize(minimumCapacity); + + [MemberNotNull(nameof(_buckets))] + [MemberNotNull(nameof(_tails))] + private void Initialize(int minimumCapacity = 0) + { + minimumCapacity = minimumCapacity <= 4 ? 4 : FishMath.NextPowerOfTwo(minimumCapacity); + // Mathf.NextPowerOfTwo(minimumCapacity); + + _buckets = new T?[minimumCapacity]; + _tails = new((uint)minimumCapacity); + _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length); + _wrapAroundMask = _buckets.Length - 1; + } + + public FishSet(IEnumerable entries) : this(0) + { + foreach (var entry in entries) + InsertEntry(entry, false); + } + + private int GetTailIndex(int entryIndex) => GetIndexForTail(entryIndex, _tails[(uint)entryIndex]); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetIndexForTail(int entryIndex, uint tail) => (entryIndex + GetJumpDistance(tail)) & _wrapAroundMask; + + #region Junk + + // private static long GetJumpDistanceLong(byte index) + // => index switch + // { + // 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, + // 8 => 8, 9 => 9, 10 => 10, 11 => 11, 12 => 12, 13 => 13, 14 => 14, + // 15 => 15, 16 => 21, 17 => 28, 18 => 36, 19 => 45, 20 => 55, 21 => 66, + // 22 => 78, 23 => 91, 24 => 105, 25 => 120, 26 => 136, 27 => 153, + // 28 => 171, 29 => 190, 30 => 210, 31 => 231, 32 => 253, 33 => 276, + // 34 => 300, 35 => 325, 36 => 351, 37 => 378, 38 => 406, 39 => 435, + // 40 => 465, 41 => 496, 42 => 528, 43 => 561, 44 => 595, 45 => 630, + // 46 => 666, 47 => 703, 48 => 741, 49 => 780, 50 => 820, 51 => 861, + // 52 => 903, 53 => 946, 54 => 990, 55 => 1035, 56 => 1081, 57 => 1128, + // 58 => 1176, 59 => 1225, 60 => 1275, 61 => 1326, 62 => 1378, 63 => 1431, + // 64 => 1485, 65 => 1540, 66 => 1596, 67 => 1653, 68 => 1711, 69 => 1770, + // 70 => 1830, 71 => 1891, 72 => 1953, 73 => 2016, 74 => 2080, 75 => 2145, + // 76 => 2211, 77 => 2278, 78 => 2346, 79 => 2415, 80 => 2485, 81 => 2556, + // 82 => 3741, 83 => 8385, 84 => 18915, 85 => 42486, 86 => 95703, 87 => 215496, + // 88 => 485605, 89 => 1091503, 90 => 2456436, 91 => 5529475, 92 => 12437578, + // 93 => 27986421, 94 => 62972253, 95 => 141700195, 96 => 318819126, 97 => 717314626, + // 98 => 1614000520, 99 => 3631437253, 100 => 8170829695, 101 => 18384318876, 102 => 41364501751, + // 103 => 93070021080, 104 => 209407709220, 105 => 471167588430, 106 => 1060127437995, 107 => 2385287281530, + // 108 => 5366895564381, 109 => 12075513791265, 110 => 27169907873235, 111 => 61132301007778, + // 112 => 137547673121001, 113 => 309482258302503, 114 => 696335090510256, 115 => 1566753939653640, + // 116 => 3525196427195653, 117 => 7931691866727775, 118 => 17846306747368716, + // 119 => 40154190394120111, 120 => 90346928493040500, 121 => 203280588949935750, + // 122 => 457381324898247375, 123 => 1029107980662394500, 124 => 2315492957028380766, + // 125 => 5209859150892887590, > 125 => throw new() + // }; + + // private static int GetJumpDistance(byte index) + // => index switch + // { + // 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 10, 11 => 11, + // 12 => 12, 13 => 13, 14 => 14, 15 => 15, 16 => 21, 17 => 28, 18 => 36, 19 => 45, 20 => 55, 21 => 66, + // 22 => 78, 23 => 91, 24 => 105, 25 => 120, 26 => 136, 27 => 153, 28 => 171, 29 => 190, 30 => 210, 31 => 231, + // 32 => 253, 33 => 276, 34 => 300, 35 => 325, 36 => 351, 37 => 378, 38 => 406, 39 => 435, 40 => 465, + // 41 => 496, 42 => 528, 43 => 561, 44 => 595, 45 => 630, 46 => 666, 47 => 703, 48 => 741, 49 => 780, + // 50 => 820, 51 => 861, 52 => 903, 53 => 946, 54 => 990, 55 => 1035, 56 => 1081, 57 => 1128, 58 => 1176, + // 59 => 1225, 60 => 1275, 61 => 1326, 62 => 1378, 63 => 1431, 64 => 1485, 65 => 1540, 66 => 1596, 67 => 1653, + // 68 => 1711, 69 => 1770, 70 => 1830, 71 => 1891, 72 => 1953, 73 => 2016, 74 => 2080, 75 => 2145, 76 => 2211, + // 77 => 2278, 78 => 2346, 79 => 2415, 80 => 2485, 81 => 2556, 82 => 3741, 83 => 8385, 84 => 18915, + // 85 => 42486, 86 => 95703, 87 => 215496, 88 => 485605, 89 => 1091503, 90 => 2456436, 91 => 5529475, + // 92 => 12437578, 93 => 27986421, 94 => 62972253, 95 => 141700195, 96 => 318819126, 97 => 717314626, + // 98 => 1614000520, 255 => int.MaxValue, > 98 => ThrowForInvalidIndex(index) + // }; + + #endregion + + private static int GetJumpDistance(uint index) + => index switch + { + 2 => 1, 3 => 2, 4 => 3, 5 => 4, 6 => 5, 7 => 8, 8 => 13, 9 => 21, 10 => 34, 11 => 55, 12 => 89, 13 => 144, + 14 => 233, 15 => 377, _ => MultiplyWithPhi(index) + }; + + [MethodImpl(MethodImplOptions.NoInlining)] + [DoesNotReturn] + private static int MultiplyWithPhi(uint index) + => throw new NotImplementedException(); // (int)(uint)Math.Round(index * FishMath.PHI); + + // private static int ThrowForInvalidIndex(byte index) + // => throw new($"Jump distance index for FishTable too large. Should be < 99, got {index} instead."); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTail(int bucketIndex) + => bucketIndex != GetBucketIndexForKeyAt(bucketIndex); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTail(T entry, int bucketIndex) + => bucketIndex != GetBucketIndex(entry); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool HasTail(int entryIndex) => !_tails.IsSoloOrEmpty(entryIndex); + + private void SetEntryWithoutTail(int bucketIndex, T entry) + { + _buckets[bucketIndex] = entry; + _tails.SetSolo(bucketIndex); + } + + private void SetEntryAsTail(int bucketIndex, T entry, int parentIndex, uint offset) + { + SetEntryWithoutTail(bucketIndex, entry); + _tails[(uint)parentIndex] = offset; + } + + private void SetParentTail(int entryIndex, uint newTail) + => _tails[(uint)GetParentBucketIndex(entryIndex)] = newTail; + + private bool InsertEntry(T entry, bool allowReplace = true, bool shifting = false) + { + var addedNewEntry = InsertEntryInternal(entry, allowReplace); + + if (shifting) + return addedNewEntry; + + _version++; + + if (!addedNewEntry) + return false; + + OnEntryAdded(entry); + return true; + } + + private void OnEntryAdded(T entry) + { + // _version++; handled separately + _count++; + EntryAdded?.Invoke(entry); + } + + /// + /// Returns true when adding a new entry, false for replacing an existing entry. AllowReplace: false causes throwing + /// instead. Does not adjust Count, Version or invoke EntryAdded. + /// + private bool InsertEntryInternal(T entry, bool allowReplace = true) + { + StartOfMethod: + var bucketIndex = GetBucketIndex(entry); + + ref var bucket = ref _buckets[bucketIndex]; + if (IsBucketEmpty(bucketIndex)) + { + SetEntryWithoutTail(bucketIndex, entry); + return true; + } + + if (TryReplaceValueOfMatchingKey(entry, allowReplace, ref bucket!)) + return false; + + if (CheckResize()) + goto StartOfMethod; + + if (IsTail(bucket, bucketIndex)) + { + var previousEntry = bucket; + var hasTail = !_tails.IsSolo(bucketIndex); + var tailingEntries = hasTail ? new T[GetTailCount(bucketIndex)] : null; + + if (hasTail) + { + var i = 0; + var tailIndex = GetTailIndex(bucketIndex); + + while (true) + { + ref var tailingBucket = ref _buckets[tailIndex]; + tailingEntries![i++] = tailingBucket!; + tailingBucket = default; + + if (!_tails.IsSoloOrEmpty(tailIndex)) + { + var nextTailIndex = GetTailIndex(tailIndex); + _tails.SetEmpty(tailIndex); + tailIndex = nextTailIndex; + } + else + { + _tails.SetEmpty(tailIndex); + break; + } + } + } + + SetParentTail(bucketIndex, Tails.SOLO); + SetEntryWithoutTail(bucketIndex, entry); + + InsertEntry(previousEntry, shifting: true); + if (hasTail) + { + for (var i = 0; i < tailingEntries!.Length; i++) + InsertEntry(tailingEntries[i], shifting: true); + } + + return true; + } + else + { + return !TryFindTailIndexAndReplace(entry, ref bucketIndex, allowReplace) + && InsertAsTail(entry, bucketIndex); + } + } + + private int GetTailCount(int index) + { + var tailCount = 0; + + while (HasTail(index)) + { + tailCount++; + index = GetTailIndex(index); + } + + return tailCount; + } + + private bool IsBucketEmpty(int bucketIndex) => IsBucketEmpty(bucketIndex, _tails, _buckets); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsBucketEmpty(int bucketIndex, Tails tails, T?[] buckets) => tails.IsEmpty(bucketIndex); + + private bool TryFindTailIndexAndReplace(T entry, ref int bucketIndex, bool allowReplace) + { + while (true) + { + if (!TryContinueWithTail(ref bucketIndex)) + return false; + + if (TryReplaceValueOfMatchingKey(entry, allowReplace, ref _buckets[bucketIndex]!)) + return true; + } + } + + private unsafe bool TryReplaceValueOfMatchingKey(T entry, bool allowReplace, ref T bucket) + { + if (!_equalityComparer(bucket, entry)) + return false; + + if (!allowReplace) + ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(entry); + + bucket = entry; + return true; + } + + private bool InsertAsTail(T entry, int bucketIndex) + { + var parentIndex = bucketIndex; + var offset = 2u; + + while (true) + { + bucketIndex = GetIndexForTail(parentIndex, offset); + + if (IsBucketEmpty(bucketIndex)) + { + SetEntryAsTail(bucketIndex, entry, parentIndex, offset); + return true; + } + + if (IsTail(bucketIndex) && offset < _tails[(uint)GetParentBucketIndex(bucketIndex)]) + break; + + if (++offset <= 15u) + continue; + + if (_buckets.Length > Count * 5) + WarnForPossiblyExcessiveResizing(entry); + + Resize(); + InsertEntry(entry, false, true); + return true; + } + + var previousEntry = _buckets[bucketIndex]; + var hasTail = !_tails.IsSolo(bucketIndex); + + var tailingEntries = hasTail ? new T?[GetTailCount(bucketIndex)] : null; + + if (hasTail) + { + var k = 0; + var tailIndex = GetTailIndex(bucketIndex); + + while (true) + { + ref var tailingBucket = ref _buckets[tailIndex]; + tailingEntries![k] = tailingBucket; + + k++; + tailingBucket = default; + + if (!_tails.IsSoloOrEmpty(tailIndex)) + { + var nextTailIndex = GetTailIndex(tailIndex); + _tails.SetEmpty(tailIndex); + tailIndex = nextTailIndex; + } + else + { + _tails.SetEmpty(tailIndex); + break; + } + } + } + + SetParentTail(bucketIndex, Tails.SOLO); + SetEntryAsTail(bucketIndex, entry, parentIndex, offset); + + InsertEntry(previousEntry!, shifting: true); + + if (hasTail) + { + for (var k = 0; k < tailingEntries!.Length; k++) + InsertEntry(tailingEntries[k]!, shifting: true); + } + + return true; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void WarnForPossiblyExcessiveResizing(T entry) + => Log.Warning($"FishTable is resizing from a large number of clashing hashCodes. Last inserted key: '{ + entry}', count: '{_count}', bucket array length: '{ + _buckets.Length}', tailing entries: '{GetTailingEntriesCount()}'"); + + private int GetTailingEntriesCount() + { + var count = 0; + for (var i = _buckets.Length; i-- > 0;) + { + if (!IsBucketEmpty(i) && IsTail(i)) + count++; + } + + return count; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool CheckResize() + { + if (_count <= (int)(_buckets.Length * _maxLoadFactor)) + return false; + + Resize(); + return true; + } + + private void Resize() + { + var oldBuckets = _buckets; + var oldTails = _tails; + + _tails = new((uint)_buckets.Length << 1); + _buckets = new T?[_buckets.Length << 1]; + + _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length); + _wrapAroundMask = _buckets.Length - 1; + + for (var i = 0; i < oldBuckets.Length; i++) + { + if (!IsBucketEmpty(i, oldTails, oldBuckets)) + InsertEntry(oldBuckets[i]!, false, true); + } + } + + [CollectionAccess(CollectionAccessType.Read)] + public unsafe bool Contains(T key) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + if (_equalityComparer(key, _buckets[bucketIndex])) + return true; + + if (!TryContinueWithTail(ref bucketIndex)) + return false; + } + } + + #region GetBucketIndexMethods + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe int GetBucketIndex(T key) => GetBucketIndex(_hashCodeGetter(key)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetBucketIndex(int hashCode) => (hashCode * FIBONACCI_HASH) >>> _bucketBitShift; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetBucketIndexForKeyAt(int index) => GetBucketIndex(_buckets[index]!); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetParentBucketIndex(int childBucketIndex) + { + var ancestorIndex = GetBucketIndexForKeyAt(childBucketIndex); + + var i = 0; + + while (true) + { + if (i++ > 32) + ThrowHelper.ThrowFailedToFindParentInvalidOperationException(this, childBucketIndex); + + var nextIndex = GetTailIndex(ancestorIndex); + if (nextIndex == childBucketIndex) + break; + + ancestorIndex = nextIndex; + } + + return ancestorIndex; + } + + #endregion + + /// + /// Returns false for solo or empty, otherwise sets the index to the tail index and returns true + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private bool TryContinueWithTail(ref int entryIndex) + { + if (!HasTail(entryIndex)) + return false; + + entryIndex = GetTailIndex(entryIndex); + return true; + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public bool Add(T key) + { + Guard.IsNotNull(key); + return InsertEntry(key, false); + } + + public void UnionWith(IEnumerable other) => throw new NotImplementedException(); + + public void IntersectWith(IEnumerable other) => throw new NotImplementedException(); + + public void ExceptWith(IEnumerable other) => throw new NotImplementedException(); + + public void SymmetricExceptWith(IEnumerable other) => throw new NotImplementedException(); + + public bool IsSubsetOf(IEnumerable other) => throw new NotImplementedException(); + + public bool IsSupersetOf(IEnumerable other) => throw new NotImplementedException(); + + public bool IsProperSupersetOf(IEnumerable other) => throw new NotImplementedException(); + + public bool IsProperSubsetOf(IEnumerable other) => throw new NotImplementedException(); + + public bool Overlaps(IEnumerable other) => throw new NotImplementedException(); + + public bool SetEquals(IEnumerable other) => throw new NotImplementedException(); + + [CollectionAccess(CollectionAccessType.ModifyExistingContent)] + public bool Remove(T key) + { + if (!RemoveInternal(key)) + return false; + + OnEntryRemoved(key); + return true; + } + + private void EmplaceWithTails(int entryIndex) + { + ref var bucket = ref _buckets[entryIndex]; + var entry = bucket; + + Span tailIndices = stackalloc int[GetTailCount(entryIndex)]; + + if (HasTail(entryIndex)) + { + tailIndices[0] = GetTailIndex(entryIndex); + for (var i = 1; i < tailIndices.Length; i++) + tailIndices[i] = GetTailIndex(tailIndices[i - 1]); + } + + if (IsTail(entry!, entryIndex)) + SetParentTail(entryIndex, Tails.SOLO); + + bucket = default; + _tails.SetEmpty(entryIndex); + InsertEntry(entry!, shifting: true); + + for (var i = 1; i < tailIndices.Length; i++) + { + var tailIndex = tailIndices[i]; + ref var tailBucket = ref _buckets[tailIndex]; + var tailEntry = tailBucket; + + tailBucket = default; + _tails.SetEmpty(tailIndex); + InsertEntry(tailEntry!, shifting: true); + } + } + + private unsafe bool RemoveInternal(T key) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var entry = ref _buckets[bucketIndex]; + + if (_equalityComparer(key, entry)) + { + var tailIndex = -1; + if (IsTail(entry!, bucketIndex)) + { + if (HasTail(bucketIndex)) + tailIndex = GetTailIndex(bucketIndex); + else + SetParentTail(bucketIndex, Tails.SOLO); + } + + entry = default; + _tails.SetEmpty(bucketIndex); + + if (tailIndex != -1) + EmplaceWithTails(tailIndex); + + return true; + } + + if (TryContinueWithTail(ref bucketIndex)) + continue; + + return false; + } + } + + void ICollection.Add(T item) => Add(item); + + [CollectionAccess(CollectionAccessType.ModifyExistingContent)] + public void Clear() + { + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (_buckets is null) + Initialize(); + + Array.Clear(_buckets, 0, _buckets.Length); + _tails.Reset(); + + _count = 0; + _version++; + } + + [CollectionAccess(CollectionAccessType.Read)] + public void CopyTo(T[] array, int arrayIndex) + { + var length = _buckets.Length; + for (var i = 0; i < length; i++) + { + if (IsBucketEmpty(i)) + continue; + + array[arrayIndex] = _buckets[i]!; + arrayIndex++; + } + } + + private void OnEntryRemoved(T entry) + { + _version++; + _count--; + EntryRemoved?.Invoke(entry); + } + + #region InterfaceMethods + + [CollectionAccess(CollectionAccessType.Read)] + public Enumerator GetEnumerator() => new(this, Enumerator.KEY_VALUE_PAIR); + + IEnumerator IEnumerable.GetEnumerator() + => new Enumerator(this, Enumerator.KEY_VALUE_PAIR); + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this, Enumerator.KEY_VALUE_PAIR); + + void ICollection.CopyTo(Array array, int index) + { + if (array is T[] typedArray) + { + CopyTo(typedArray, index); + return; + } + + var length = _buckets.Length; + for (var i = 0; i < length; i++) + { + if (IsBucketEmpty(i)) + continue; + + ((IList)array)[index] = _buckets[i]; + index++; + } + } + + #endregion + + #region Structs + + internal struct Tails + { + public const uint + EMPTY = 0u, + SOLO = 1u; + + private NibbleArray _values; + + public Tails(uint length) => _values = new(length); + + public uint this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _values[index]; + + set => _values[index] = value; + } + + public void Reset() => _values.Clear(); //_values.Initialize(15u); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsEmpty(int index) => _values[(uint)index] == EMPTY; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsSolo(int index) => _values[(uint)index] == SOLO; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsSoloOrEmpty(int index) => _values[(uint)index] <= 1u; + + public void SetSolo(int index) => _values[(uint)index] = SOLO; + + public void SetEmpty(int index) => _values[(uint)index] = EMPTY; + } + + public record struct Enumerator : IEnumerator + { + private readonly FishSet _dictionary; + private readonly int _version; + private uint _index; + private T? _current; + + internal const int DICT_ENTRY = 1; + internal const int KEY_VALUE_PAIR = 2; + + internal Enumerator(FishSet dictionary, int getEnumeratorRetType) + { + _dictionary = dictionary; + _version = dictionary._version; + _index = 0u; + _current = default; + } + + public bool MoveNext() + { + if (_version != _dictionary._version) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); + + while (_index < (uint)_dictionary._buckets.Length) + { + if (_dictionary.IsBucketEmpty((int)_index++)) + continue; + + _current = _dictionary._buckets[_index - 1]!; + return true; + } + + _index = (uint)_dictionary._buckets.Length + 1u; + _current = default; + return false; + } + + [CollectionAccess(CollectionAccessType.Read)] + public T Current => _current!; + + public void Dispose() + { + } + + object IEnumerator.Current + { + get + { + if (_index == 0u || _index == (uint)_dictionary._buckets.Length + 1u) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return _current!; + } + } + + void IEnumerator.Reset() + { + if (_version != _dictionary._version) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); + + _index = 0u; + _current = default; + } + } + + #endregion + + private static class ThrowHelper + { + [DoesNotReturn] + internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() + => throw new InvalidOperationException("Collection was modified; enumeration operation may not execute."); + + [DoesNotReturn] + internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() + => throw new InvalidOperationException("Enumeration has either not started or has already finished."); + + [DoesNotReturn] + internal static void ThrowWrongKeyTypeArgumentException(object? key) + { + Guard.IsNotNull(key); + throw new ArgumentException($"The value \"{key}\" is not of type \"{ + typeof(T)}\" and cannot be used in this generic collection.", + nameof(key)); + } + + [DoesNotReturn] + internal static void ThrowAddingDuplicateWithKeyArgumentException(T key) + { + Guard.IsNotNull(key); + ThrowAddingDuplicateWithKeyArgumentException((object)key); + } + + [DoesNotReturn] + internal static unsafe void ThrowFailedToFindParentInvalidOperationException(FishSet fishTable, + int childBucketIndex) + { + var entry = fishTable._buckets[childBucketIndex]; + throw new InvalidOperationException($"Failed to find parent index in FishTable for key: '{ + entry}', hashCode: '{fishTable._hashCodeGetter(entry)}', count: '{ + fishTable._count}', bucket array length: '{fishTable._buckets.Length}', tailing entries: '{ + fishTable.GetTailingEntriesCount()}'"); + } + + [DoesNotReturn] + private static void ThrowAddingDuplicateWithKeyArgumentException(object key) + => throw new ArgumentException($"An item with the same key has already been added. Key: {key}"); + } +} +#pragma warning restore CS8766, CS8767 \ No newline at end of file diff --git a/Source/FisheryLib/Collections/FishTable.cs b/Source/FisheryLib/Collections/FishTable.cs new file mode 100644 index 0000000..718249d --- /dev/null +++ b/Source/FisheryLib/Collections/FishTable.cs @@ -0,0 +1,1475 @@ +// Copyright (c) 2023 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// Loosely based on https://github.com/matthewcrews/FastDictionaryTest/tree/main +// which itself is based on +// https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/ + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; +using FisheryLib.FunctionPointers; +using FisheryLib.Utility; +using JetBrains.Annotations; + +namespace FisheryLib.Collections; + +#pragma warning disable CS8766, CS8767 +[PublicAPI] +[StructLayout(LayoutKind.Sequential)] +public class FishTable : IDictionary, IDictionary, IReadOnlyDictionary +{ + private const int FIBONACCI_HASH = -1640531527; // unchecked((int)(uint)Math.Round(uint.MaxValue / FishMath.PHI)); + + internal Entry[] _buckets; + + private unsafe delegate* _keyHashCodeByRefGetter = GetHashCodeByRef.Default; + private unsafe delegate* _keyEqualityByRefComparer = EqualsByRef.Default; + + private int + _bucketBitShift, + _count; + + private unsafe delegate* _keyHashCodeGetter = GetHashCode.Default; + private unsafe delegate* _keyEqualityComparer = Equals.Default; + + internal Tails _tails; + + private int + _wrapAroundMask, + _version; + + private float _maxLoadFactor = 0.5f; + + public ICollection Keys => throw new NotImplementedException(); + + public ICollection Values => throw new NotImplementedException(); + + public int Version + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _version; + set + { + Guard.IsGreaterThan(value, _version); + _version = value; + } + } + + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _count; + } + + public bool IsReadOnly => false; + + public unsafe uint SizeEstimate + => GetType().ComputeManagedObjectSizeEstimate() + + ((uint)sizeof(Entry) * (uint)_buckets.Length) + + ((_tails.Length + 1u) >> 1); + + public event Action>? + EntryAdded, + EntryRemoved; + + public delegate void EntryEventHandler(TKey key, ref TValue value); + + public event Action? KeyAdded + { + add => AddEvent(ref EntryAdded, value); + remove => RemoveEvent(ref EntryAdded, value); + } + + public event Action? KeyRemoved + { + add => AddEvent(ref EntryRemoved, value); + remove => RemoveEvent(ref EntryRemoved, value); + } + + public event Action? ValueAdded + { + add => AddEvent(ref EntryAdded, value); + remove => RemoveEvent(ref EntryAdded, value); + } + + public event Action? ValueRemoved + { + add => AddEvent(ref EntryRemoved, value); + remove => RemoveEvent(ref EntryRemoved, value); + } + + private static void AddEvent(ref Action>? @event, Action? value) + where THandler : IEventHandler + { + if (value != null) + @event += Reflection.New>(value).Invoke; + } + + private static void RemoveEvent(ref Action>? @event, Action? value) + { + if (@event is null) + return; + + var delegates = @event.GetInvocationList(); + for (var i = delegates.Length; i-- > 0;) + { + if (delegates[i].Target is not IEventHandler handler || handler.Action != value) + continue; + + @event -= (Action>)delegates[i]; + return; + } + } + + private interface IEventHandler + { + public Action Action { get; } + public void Invoke(KeyValuePair pair); + } + + private record KeyEventHandler(Action Action) : IEventHandler + { + public void Invoke(KeyValuePair pair) => Action(pair.Key); + } + + private record ValueEventHandler(Action Action) : IEventHandler + { + public void Invoke(KeyValuePair pair) => Action(pair.Value); + } + + public float MaxLoadFactor + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _maxLoadFactor; + set + { + Guard.IsInRange(value, 0f, 1f); + _maxLoadFactor = value; + } + } + + ICollection IDictionary.Keys => throw new NotImplementedException(); + + ICollection IDictionary.Values => throw new NotImplementedException(); + + bool IDictionary.IsFixedSize => false; + + object ICollection.SyncRoot => this; // matching System.Collections.Generic.Dictionary + + bool ICollection.IsSynchronized => false; + + IEnumerable IReadOnlyDictionary.Keys => throw new NotImplementedException(); + + IEnumerable IReadOnlyDictionary.Values => throw new NotImplementedException(); + + object? IDictionary.this[object key] + { + get => this[AssertKeyType(key)]; + set => this[AssertKeyType(key)] = AssertValueType(value); + } + + private static TKey AssertKeyType(object key) + { + if (key is TKey tKey) + return tKey; + else if (key != null!) + ThrowHelper.ThrowWrongKeyTypeArgumentException(key); + + return default!; + } + + private static TValue AssertValueType(object? value) + { + if (value is TValue tValue) + return tValue; + else if (value != null!) + ThrowHelper.ThrowWrongValueTypeArgumentException(value); + + return default!; + } + + public unsafe TValue? this[TKey key] + { + [CollectionAccess(CollectionAccessType.Read)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, bucket.Key)) + return bucket.Value; + + ContinueWithTailOrThrow(ref bucketIndex, key); + } + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + set => InsertEntry(key, value); + } + + public FishTable() : this(0) + { + } + + public FishTable(int minimumCapacity) => Initialize(minimumCapacity); + + [MemberNotNull(nameof(_buckets))] + [MemberNotNull(nameof(_tails))] + private void Initialize(int minimumCapacity = 0) + { + minimumCapacity = minimumCapacity <= 4 ? 4 : FishMath.NextPowerOfTwo(minimumCapacity); + // Mathf.NextPowerOfTwo(minimumCapacity); + + _buckets = new Entry[minimumCapacity]; + _tails = new((uint)minimumCapacity); + _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length); + _wrapAroundMask = _buckets.Length - 1; + } + + public FishTable(IEnumerable> entries) : this(0) + => AddRange(entries); + + private int GetTailIndex(int entryIndex) => GetIndexForTail(entryIndex, _tails[(uint)entryIndex]); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetIndexForTail(int entryIndex, uint tail) => (entryIndex + GetJumpDistance(tail)) & _wrapAroundMask; + + #region Junk + + // private static long GetJumpDistanceLong(byte index) + // => index switch + // { + // 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, + // 8 => 8, 9 => 9, 10 => 10, 11 => 11, 12 => 12, 13 => 13, 14 => 14, + // 15 => 15, 16 => 21, 17 => 28, 18 => 36, 19 => 45, 20 => 55, 21 => 66, + // 22 => 78, 23 => 91, 24 => 105, 25 => 120, 26 => 136, 27 => 153, + // 28 => 171, 29 => 190, 30 => 210, 31 => 231, 32 => 253, 33 => 276, + // 34 => 300, 35 => 325, 36 => 351, 37 => 378, 38 => 406, 39 => 435, + // 40 => 465, 41 => 496, 42 => 528, 43 => 561, 44 => 595, 45 => 630, + // 46 => 666, 47 => 703, 48 => 741, 49 => 780, 50 => 820, 51 => 861, + // 52 => 903, 53 => 946, 54 => 990, 55 => 1035, 56 => 1081, 57 => 1128, + // 58 => 1176, 59 => 1225, 60 => 1275, 61 => 1326, 62 => 1378, 63 => 1431, + // 64 => 1485, 65 => 1540, 66 => 1596, 67 => 1653, 68 => 1711, 69 => 1770, + // 70 => 1830, 71 => 1891, 72 => 1953, 73 => 2016, 74 => 2080, 75 => 2145, + // 76 => 2211, 77 => 2278, 78 => 2346, 79 => 2415, 80 => 2485, 81 => 2556, + // 82 => 3741, 83 => 8385, 84 => 18915, 85 => 42486, 86 => 95703, 87 => 215496, + // 88 => 485605, 89 => 1091503, 90 => 2456436, 91 => 5529475, 92 => 12437578, + // 93 => 27986421, 94 => 62972253, 95 => 141700195, 96 => 318819126, 97 => 717314626, + // 98 => 1614000520, 99 => 3631437253, 100 => 8170829695, 101 => 18384318876, 102 => 41364501751, + // 103 => 93070021080, 104 => 209407709220, 105 => 471167588430, 106 => 1060127437995, 107 => 2385287281530, + // 108 => 5366895564381, 109 => 12075513791265, 110 => 27169907873235, 111 => 61132301007778, + // 112 => 137547673121001, 113 => 309482258302503, 114 => 696335090510256, 115 => 1566753939653640, + // 116 => 3525196427195653, 117 => 7931691866727775, 118 => 17846306747368716, + // 119 => 40154190394120111, 120 => 90346928493040500, 121 => 203280588949935750, + // 122 => 457381324898247375, 123 => 1029107980662394500, 124 => 2315492957028380766, + // 125 => 5209859150892887590, > 125 => throw new() + // }; + + // private static int GetJumpDistance(byte index) + // => index switch + // { + // 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 10, 11 => 11, + // 12 => 12, 13 => 13, 14 => 14, 15 => 15, 16 => 21, 17 => 28, 18 => 36, 19 => 45, 20 => 55, 21 => 66, + // 22 => 78, 23 => 91, 24 => 105, 25 => 120, 26 => 136, 27 => 153, 28 => 171, 29 => 190, 30 => 210, 31 => 231, + // 32 => 253, 33 => 276, 34 => 300, 35 => 325, 36 => 351, 37 => 378, 38 => 406, 39 => 435, 40 => 465, + // 41 => 496, 42 => 528, 43 => 561, 44 => 595, 45 => 630, 46 => 666, 47 => 703, 48 => 741, 49 => 780, + // 50 => 820, 51 => 861, 52 => 903, 53 => 946, 54 => 990, 55 => 1035, 56 => 1081, 57 => 1128, 58 => 1176, + // 59 => 1225, 60 => 1275, 61 => 1326, 62 => 1378, 63 => 1431, 64 => 1485, 65 => 1540, 66 => 1596, 67 => 1653, + // 68 => 1711, 69 => 1770, 70 => 1830, 71 => 1891, 72 => 1953, 73 => 2016, 74 => 2080, 75 => 2145, 76 => 2211, + // 77 => 2278, 78 => 2346, 79 => 2415, 80 => 2485, 81 => 2556, 82 => 3741, 83 => 8385, 84 => 18915, + // 85 => 42486, 86 => 95703, 87 => 215496, 88 => 485605, 89 => 1091503, 90 => 2456436, 91 => 5529475, + // 92 => 12437578, 93 => 27986421, 94 => 62972253, 95 => 141700195, 96 => 318819126, 97 => 717314626, + // 98 => 1614000520, 255 => int.MaxValue, > 98 => ThrowForInvalidIndex(index) + // }; + + #endregion + + private static int GetJumpDistance(uint index) + => index switch + { + 2 => 1, 3 => 2, 4 => 3, 5 => 4, 6 => 5, 7 => 8, 8 => 13, 9 => 21, 10 => 34, 11 => 55, 12 => 89, 13 => 144, + 14 => 233, 15 => 377, _ => MultiplyWithPhi(index) + }; + + [MethodImpl(MethodImplOptions.NoInlining)] + [DoesNotReturn] + private static int MultiplyWithPhi(uint index) + => throw new NotImplementedException(); // (int)(uint)Math.Round(index * FishMath.PHI); + + // private static int ThrowForInvalidIndex(byte index) + // => throw new($"Jump distance index for FishTable too large. Should be < 99, got {index} instead."); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTail(int bucketIndex) + => bucketIndex != GetBucketIndexForKeyAt(bucketIndex); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTail(ref Entry entry, int bucketIndex) + => bucketIndex != GetBucketIndex(entry.Key); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool HasTail(int entryIndex) => !_tails.IsSoloOrEmpty(entryIndex); + + private void SetEntryWithoutTail(int bucketIndex, in Entry entry) + { + _buckets[bucketIndex] = entry; + _tails.SetSolo(bucketIndex); + } + + private void SetEntryAsTail(int bucketIndex, in Entry entry, int parentIndex, uint offset) + { + SetEntryWithoutTail(bucketIndex, entry); + _tails[(uint)parentIndex] = offset; + } + + private void SetParentTail(int entryIndex, uint newTail) + => _tails[(uint)GetParentBucketIndex(entryIndex)] = newTail; + + private void InsertEntry(TKey key, TValue? value, bool allowReplace = true, bool shifting = false) + => InsertEntry(new(key, value), allowReplace, shifting); + + private void InsertEntry(in Entry entry, bool allowReplace = true, bool shifting = false) + { + var addedNewEntry = InsertEntryInternal(entry, allowReplace); + + if (shifting) + return; + + _version++; + + if (!addedNewEntry) + return; + + OnEntryAdded(entry.AsKeyValuePair()); + } + + private void OnEntryAdded(in KeyValuePair entry) + { + // _version++; handled separately + _count++; + EntryAdded?.Invoke(entry); + } + + /// + /// Returns true when adding a new entry, false for replacing an existing entry. AllowReplace: false causes throwing + /// instead. Does not adjust Count, Version or invoke EntryAdded. + /// + private bool InsertEntryInternal(in Entry entry, bool allowReplace = true) + { + StartOfMethod: + var bucketIndex = GetBucketIndex(entry.Key); + + ref var bucket = ref _buckets[bucketIndex]; + if (IsBucketEmpty(bucketIndex)) + { + SetEntryWithoutTail(bucketIndex, entry); + return true; + } + + if (TryReplaceValueOfMatchingKey(entry, allowReplace, ref bucket)) + return false; + + if (CheckResize()) + goto StartOfMethod; + + if (IsTail(ref bucket, bucketIndex)) + { + var previousEntry = bucket; + var hasTail = !_tails.IsSolo(bucketIndex); + var tailingEntries = hasTail ? new Entry[GetTailCount(bucketIndex)] : null; + + if (hasTail) + { + var i = 0; + var tailIndex = GetTailIndex(bucketIndex); + + while (true) + { + ref var tailingBucket = ref _buckets[tailIndex]; + tailingEntries![i++] = tailingBucket; + tailingBucket = default; + + if (!_tails.IsSoloOrEmpty(tailIndex)) + { + var nextTailIndex = GetTailIndex(tailIndex); + _tails.SetEmpty(tailIndex); + tailIndex = nextTailIndex; + } + else + { + _tails.SetEmpty(tailIndex); + break; + } + } + } + + SetParentTail(bucketIndex, Tails.SOLO); + SetEntryWithoutTail(bucketIndex, entry); + + InsertEntry(previousEntry, shifting: true); + if (hasTail) + { + for (var i = 0; i < tailingEntries!.Length; i++) + InsertEntry(tailingEntries[i], shifting: true); + } + + return true; + } + else + { + return !TryFindTailIndexAndReplace(entry, ref bucketIndex, allowReplace) + && InsertAsTail(entry, bucketIndex); + } + } + + private int GetTailCount(int index) + { + var tailCount = 0; + + while (HasTail(index)) + { + tailCount++; + index = GetTailIndex(index); + } + + return tailCount; + } + + private bool IsBucketEmpty(int bucketIndex) => IsBucketEmpty(bucketIndex, _tails, _buckets); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsBucketEmpty(int bucketIndex, Tails tails, Entry[] buckets) + => tails.IsEmpty(bucketIndex) && VerifyAgainstNullBucket(bucketIndex, tails, buckets); + + private unsafe bool VerifyAgainstNullBucket(int bucketIndex, Tails tails, Entry[] buckets) + { + ref var bucket = ref buckets[bucketIndex]; + + if (!_keyEqualityComparer(bucket.Key, default)) + ThrowHelper.ThrowEmptyBucketKeyInvalidOperationException(bucketIndex, bucket); + + if (bucket.Value.Equals(default)) + return true; + + // GetReference methods can get here when using a default key and accessing the returned ref + tails.SetSolo(bucketIndex); + OnEntryAdded(bucket.AsKeyValuePair()); // technically late, but it's an edge case and there's + return false; // no good workaround without performance hit + } + + private bool TryFindTailIndexAndReplace(in Entry entry, ref int bucketIndex, bool allowReplace) + { + while (true) + { + if (!TryContinueWithTail(ref bucketIndex)) + return false; + + if (TryReplaceValueOfMatchingKey(entry, allowReplace, ref _buckets[bucketIndex])) + return true; + } + } + + private unsafe bool TryReplaceValueOfMatchingKey(in Entry entry, bool allowReplace, ref Entry bucket) + { + if (!_keyEqualityComparer(bucket.Key, entry.Key)) + return false; + + if (!allowReplace) + ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(entry.Key); + + bucket.Value = entry.Value; + return true; + } + + private bool InsertAsTail(in Entry entry, int bucketIndex) + { + var parentIndex = bucketIndex; + var offset = 2u; + + while (true) + { + bucketIndex = GetIndexForTail(parentIndex, offset); + + if (IsBucketEmpty(bucketIndex)) + { + SetEntryAsTail(bucketIndex, entry, parentIndex, offset); + return true; + } + + if (IsTail(bucketIndex) && offset < _tails[(uint)GetParentBucketIndex(bucketIndex)]) + break; + + if (++offset <= 15u) + continue; + + if (_buckets.Length > Count * 5) + WarnForPossiblyExcessiveResizing(entry); + + Resize(); + InsertEntry(entry, false, true); + return true; + } + + var previousEntry = _buckets[bucketIndex]; + var hasTail = !_tails.IsSolo(bucketIndex); + + var tailingEntries = hasTail ? new Entry[GetTailCount(bucketIndex)] : null; + + if (hasTail) + { + var k = 0; + var tailIndex = GetTailIndex(bucketIndex); + + while (true) + { + ref var tailingBucket = ref _buckets[tailIndex]; + tailingEntries![k] = tailingBucket; + + k++; + tailingBucket = default; + + if (!_tails.IsSoloOrEmpty(tailIndex)) + { + var nextTailIndex = GetTailIndex(tailIndex); + _tails.SetEmpty(tailIndex); + tailIndex = nextTailIndex; + } + else + { + _tails.SetEmpty(tailIndex); + break; + } + } + } + + SetParentTail(bucketIndex, Tails.SOLO); + SetEntryAsTail(bucketIndex, entry, parentIndex, offset); + + InsertEntry(previousEntry, shifting: true); + + if (hasTail) + { + for (var k = 0; k < tailingEntries!.Length; k++) + InsertEntry(tailingEntries[k], shifting: true); + } + + return true; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void WarnForPossiblyExcessiveResizing(Entry entry) + => Log.Warning($"FishTable is resizing from a large number of clashing hashCodes. Last inserted key: '{ + entry.Key}', value: '{entry.Value}', count: '{_count}', bucket array length: '{ + _buckets.Length}', tailing entries: '{GetTailingEntriesCount()}'"); + + private int GetTailingEntriesCount() + { + var count = 0; + for (var i = _buckets.Length; i-- > 0;) + { + if (!IsBucketEmpty(i) && IsTail(i)) + count++; + } + + return count; + } + + public void EnsureCapacity(int minimumSize) + { + if (_buckets.Length >= minimumSize) + return; + + Resize(FishMath.NextPowerOfTwo(minimumSize)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool CheckResize() + { + if (_count <= (int)(_buckets.Length * _maxLoadFactor)) + return false; + + Resize(); + return true; + } + + private void Resize() => Resize(_buckets.Length << 1); + + private void Resize(int newSize) + { + var oldBuckets = _buckets; + var oldTails = _tails; + + _tails = new((uint)newSize); + _buckets = new Entry[newSize]; + + _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)newSize); + _wrapAroundMask = _buckets.Length - 1; + + for (var i = 0; i < oldBuckets.Length; i++) + { + if (!IsBucketEmpty(i, oldTails, oldBuckets)) + InsertEntry(oldBuckets[i], false, true); + } + } + + #region GetterMethods + + [CollectionAccess(CollectionAccessType.Read)] + public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, bucket.Key)) + { + value = bucket.Value!; + return true; + } + + if (TryContinueWithTail(ref bucketIndex)) + continue; + + value = default; + return false; + } + } + + [CollectionAccess(CollectionAccessType.Read)] + public unsafe TValue? TryGetValue(TKey key) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, bucket.Key)) + return bucket.Value; + + if (!TryContinueWithTail(ref bucketIndex)) + return default; + } + } + + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.UpdatedContent)] + public unsafe TValue GetOrAdd(TKey key) + { + StartOfMethod: + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, bucket.Key)) + return bucket.Value!; + + if (!ContinueWithTailOrAddNew(ref bucketIndex, key)) + goto StartOfMethod; + } + } + + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.UpdatedContent)] + public unsafe TValue GetOrAdd(ref TKey key) + { + StartOfMethod: + var bucketIndex = GetBucketIndex(ref key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityByRefComparer(ref key, ref bucket.Key)) + return bucket.Value!; + + if (!ContinueWithTailOrAddNew(ref bucketIndex, ref key)) + goto StartOfMethod; + } + } + + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.UpdatedContent)] + public unsafe ref TValue GetOrAddReference(TKey key) + { + StartOfMethod: + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, bucket.Key)) + return ref bucket.Value!; + + if (!ContinueWithTailOrAddNew(ref bucketIndex, key)) + goto StartOfMethod; + } + } + + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.UpdatedContent)] + public unsafe ref TValue GetOrAddReference(ref TKey key) + { + StartOfMethod: + var bucketIndex = GetBucketIndex(ref key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityByRefComparer(ref key, ref bucket.Key)) + return ref bucket.Value!; + + if (!ContinueWithTailOrAddNew(ref bucketIndex, ref key)) + goto StartOfMethod; + } + } + + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.ModifyExistingContent)] + public unsafe ref TValue GetReference(TKey key) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, bucket.Key)) + return ref bucket.Value!; + + ContinueWithTailOrThrow(ref bucketIndex, key); + } + } + + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.ModifyExistingContent)] + public unsafe ref TValue GetReference(ref TKey key) + { + var bucketIndex = GetBucketIndex(ref key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityByRefComparer(ref key, ref bucket.Key)) + return ref bucket.Value!; + + ContinueWithTailOrThrow(ref bucketIndex, ref key); + } + } + + /// + /// Returns a reference to the value field of an entry if the key exists and an Unsafe.NullRef{TValue} if not. + /// Must be checked with Unsafe.IsNullRef before assigning to a regular var or field without ref. + /// + /// The key + /// ref TValue or Unsafe.NullRef{TValue} + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.ModifyExistingContent)] + public unsafe ref TValue? TryGetReferenceUnsafe(TKey key) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, bucket.Key)) + return ref bucket.Value; + + if (!TryContinueWithTail(ref bucketIndex)) + return ref Unsafe.NullRef(); + } + } + + [CollectionAccess(CollectionAccessType.Read | CollectionAccessType.ModifyExistingContent)] + public unsafe ref TValue? TryGetReferenceUnsafe(ref TKey key) + { + var bucketIndex = GetBucketIndex(ref key); + + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + + if (_keyEqualityByRefComparer(ref key, ref bucket.Key)) + return ref bucket.Value; + + if (!TryContinueWithTail(ref bucketIndex)) + return ref Unsafe.NullRef(); + } + } + + #endregion + + [CollectionAccess(CollectionAccessType.Read)] + public unsafe bool ContainsKey(TKey key) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + if (_keyEqualityComparer(key, _buckets[bucketIndex].Key)) + return true; + + if (!TryContinueWithTail(ref bucketIndex)) + return false; + } + } + + #region GetBucketIndexMethods + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe int GetBucketIndex(ref TKey key) => GetBucketIndex(_keyHashCodeByRefGetter(ref key)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe int GetBucketIndex(TKey key) => GetBucketIndex(_keyHashCodeGetter(key)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetBucketIndex(int hashCode) => (hashCode * FIBONACCI_HASH) >>> _bucketBitShift; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetBucketIndexForKeyAt(int index) => GetBucketIndex(_buckets[index].Key); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetParentBucketIndex(int childBucketIndex) + { + var ancestorIndex = GetBucketIndexForKeyAt(childBucketIndex); + + var i = 0; + + while (true) + { + if (i++ > 32) + ThrowHelper.ThrowFailedToFindParentInvalidOperationException(this, childBucketIndex); + + var nextIndex = GetTailIndex(ancestorIndex); + if (nextIndex == childBucketIndex) + break; + + ancestorIndex = nextIndex; + } + + return ancestorIndex; + } + + #endregion + + #region ContinueWithTailMethods + + /// + /// Tries setting the index to the tail's index and returns true on success. If none exists, inserts a new entry + /// and returns false + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private bool ContinueWithTailOrAddNew(ref int entryIndex, TKey key) + { + if (TryContinueWithTail(ref entryIndex)) + return true; + + this[key] = Reflection.New(); + return false; + } + + /// + /// Tries setting the index to the tail's index and returns true on success. If none exists, inserts a new entry + /// and returns false + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private bool ContinueWithTailOrAddNew(ref int entryIndex, ref TKey key) + { + if (TryContinueWithTail(ref entryIndex)) + return true; + + this[key] = Reflection.New(); + return false; + } + + /// + /// Tries setting the index to the tail's index. If none exists, throws instead + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private void ContinueWithTailOrThrow(ref int entryIndex, TKey key) + { + if (!TryContinueWithTail(ref entryIndex)) + ThrowHelper.ThrowKeyNotFoundException(key); + } + + /// + /// Tries setting the index to the tail's index. If none exists, throws instead + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private void ContinueWithTailOrThrow(ref int entryIndex, ref TKey key) + { + if (!TryContinueWithTail(ref entryIndex)) + ThrowHelper.ThrowKeyNotFoundException(key); + } + + /// + /// Returns false for solo or empty, otherwise sets the index to the tail index and returns true + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private bool TryContinueWithTail(ref int entryIndex) + { + if (!HasTail(entryIndex)) + return false; + + entryIndex = GetTailIndex(entryIndex); + return true; + } + + #endregion + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void Add(TKey key, TValue value) + { + Guard.IsNotNull(key); + InsertEntry(key, value, false); + } + + [CollectionAccess(CollectionAccessType.ModifyExistingContent)] + public bool Remove(TKey key) + { + if (!RemoveInternal(key, out var removedEntry)) + return false; + + OnEntryRemoved(removedEntry.AsKeyValuePair()); + return true; + } + + private void EmplaceWithTails(int entryIndex) + { + ref var bucket = ref _buckets[entryIndex]; + var entry = bucket; + + Span tailIndices = stackalloc int[GetTailCount(entryIndex)]; + + if (HasTail(entryIndex)) + { + tailIndices[0] = GetTailIndex(entryIndex); + for (var i = 1; i < tailIndices.Length; i++) + tailIndices[i] = GetTailIndex(tailIndices[i - 1]); + } + + if (IsTail(ref entry, entryIndex)) + SetParentTail(entryIndex, Tails.SOLO); + + bucket = default; + _tails.SetEmpty(entryIndex); + InsertEntry(entry, shifting: true); + + for (var i = 1; i < tailIndices.Length; i++) + { + var tailIndex = tailIndices[i]; + ref var tailBucket = ref _buckets[tailIndex]; + var tailEntry = tailBucket; + + tailBucket = default; + _tails.SetEmpty(tailIndex); + InsertEntry(tailEntry, shifting: true); + } + } + + private unsafe bool RemoveInternal(TKey key, out Entry removedEntry, bool checkValue = false, + TValue? value = default) + { + var bucketIndex = GetBucketIndex(key); + + while (true) + { + ref var entry = ref _buckets[bucketIndex]; + + if (_keyEqualityComparer(key, entry.Key)) + { + if (checkValue && !value.Equals(entry.Value)) + goto OnFailure; + + removedEntry = entry; + + var tailIndex = -1; + if (IsTail(ref entry, bucketIndex)) + { + if (HasTail(bucketIndex)) + tailIndex = GetTailIndex(bucketIndex); + else + SetParentTail(bucketIndex, Tails.SOLO); + } + + entry.Key = default!; + entry.Value = default; + _tails.SetEmpty(bucketIndex); + + if (tailIndex != -1) + EmplaceWithTails(tailIndex); + + return true; + } + + if (TryContinueWithTail(ref bucketIndex)) + continue; + + OnFailure: + Unsafe.SkipInit(out removedEntry); + return false; + } + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void Add(KeyValuePair item) => Add(item.Key, item.Value); + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void AddRange(IList> range) + { + Guard.IsNotNull(range); + + EnsureCapacity((int)(range.Count * 1.5f)); + for (var i = range.Count; i-- > 0;) + Add(range[i]); + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void AddRange(IEnumerable> range) + { + Guard.IsNotNull(range); + + if (range is IList> iList) + AddRange(iList); + else + AddRangeFromEnumerable(range); + } + + private void AddRangeFromEnumerable(IEnumerable> range) + { + Guard.IsNotNull(range); + + foreach (var item in range) + Add(item); + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void AddRange(IList range, Func keySelector, + Func valueSelector) + { + Guard.IsNotNull(range); + Guard.IsNotNull(keySelector); + Guard.IsNotNull(valueSelector); + + EnsureCapacity((int)(range.Count * 1.5f)); + for (var i = range.Count; i-- > 0;) + { + var item = range[i]; + Add(keySelector(item), valueSelector(item)); + } + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void AddRange(IEnumerable range, Func keySelector, + Func valueSelector) + { + Guard.IsNotNull(range); + Guard.IsNotNull(keySelector); + Guard.IsNotNull(valueSelector); + + if (range is IList iList) + AddRange(iList, keySelector, valueSelector); + else + AddRangeFromEnumerable(range, keySelector, valueSelector); + } + + private void AddRangeFromEnumerable(IEnumerable range, Func keySelector, + Func valueSelector) + { + Guard.IsNotNull(range); + Guard.IsNotNull(keySelector); + Guard.IsNotNull(valueSelector); + + foreach (var item in range) + Add(keySelector(item), valueSelector(item)); + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void AddRange(IList keys, IList values) + { + Guard.IsNotNull(keys); + Guard.IsNotNull(values); + + var count = keys.Count; + if (count != values.Count) + ThrowHelper.ThrowInvalidKeysValuesSizeArgumentException(); + + EnsureCapacity((int)(count * 1.5f)); + for (var i = count; i-- > 0;) + Add(keys[i], values[i]); + } + + [CollectionAccess(CollectionAccessType.UpdatedContent)] + public void AddRange(IEnumerable keys, IEnumerable values) + { + Guard.IsNotNull(keys); + Guard.IsNotNull(values); + + if (keys is IList keysList && values is IList valuesList) + AddRange(keysList, valuesList); + else + AddRangeFromEnumerable(keys, values); + } + + private void AddRangeFromEnumerable(IEnumerable keys, IEnumerable values) + { + Guard.IsNotNull(keys); + Guard.IsNotNull(values); + + using var keyEnumerator = keys.GetEnumerator(); + using var valueEnumerator = values.GetEnumerator(); + + while (keyEnumerator.MoveNext()) + { + if (!valueEnumerator.MoveNext()) + ThrowHelper.ThrowInvalidKeysValuesSizeArgumentException(); + + Add(keyEnumerator.Current, valueEnumerator.Current); + } + } + + [CollectionAccess(CollectionAccessType.ModifyExistingContent)] + public void Clear() + { + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (_buckets is null) + Initialize(); + + Array.Clear(_buckets, 0, _buckets.Length); + _tails.Reset(); + + _count = 0; + _version++; + } + + [CollectionAccess(CollectionAccessType.Read)] + public bool Contains(KeyValuePair item) + => TryGetValue(item.Key, out var value) + && value.Equals(item.Value); + + [CollectionAccess(CollectionAccessType.Read)] + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + var length = _buckets.Length; + for (var i = 0; i < length; i++) + { + if (IsBucketEmpty(i)) + continue; + + array[arrayIndex] = _buckets[i].AsKeyValuePair()!; + arrayIndex++; + } + } + + [CollectionAccess(CollectionAccessType.ModifyExistingContent)] + public bool Remove(KeyValuePair item) + { + if (!RemoveInternal(item.Key, out _, true, item.Value)) + return false; + + OnEntryRemoved(item); + return true; + } + + private void OnEntryRemoved(in KeyValuePair entry) + { + _version++; + _count--; + EntryRemoved?.Invoke(entry); + } + + #region InterfaceMethods + + [CollectionAccess(CollectionAccessType.Read)] + public Enumerator GetEnumerator() => new(this, Enumerator.KEY_VALUE_PAIR); + + IEnumerator> IEnumerable>.GetEnumerator() + => new Enumerator(this, Enumerator.KEY_VALUE_PAIR); + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this, Enumerator.KEY_VALUE_PAIR); + + bool IDictionary.Contains(object key) + { + Guard.IsNotNull(key); + + return key is TKey tKey && ContainsKey(tKey); + } + + void IDictionary.Add(object key, object value) => Add(AssertKeyType(key), AssertValueType(value)); + + IDictionaryEnumerator IDictionary.GetEnumerator() => new Enumerator(this, Enumerator.DICT_ENTRY); + + void IDictionary.Remove(object key) + { + Guard.IsNotNull(key); + + if (key is TKey tKey) + Remove(tKey); + } + + void ICollection.CopyTo(Array array, int index) + { + if (array is KeyValuePair[] typedArray) + { + CopyTo(typedArray, index); + return; + } + + var length = _buckets.Length; + for (var i = 0; i < length; i++) + { + if (IsBucketEmpty(i)) + continue; + + ((IList)array)[index] = _buckets[i].AsKeyValuePair(); + index++; + } + } + + #endregion + + #region Structs + + // [StructLayout(LayoutKind.Sequential, Pack = 1)] + // matches KeyValuePair and gets reinterpret cast into that in the Enumerator + internal struct Entry + { + public TKey Key; + public TValue? Value; + + public Entry(TKey key, TValue? value) + { + Key = key; + Value = value; + } + + [Pure] + [UnscopedRef] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [SecuritySafeCritical] + public ref KeyValuePair AsKeyValuePair() + => ref Unsafe.As>(ref this); + } + + internal struct Tails + { + public const uint + EMPTY = 0u, + SOLO = 1u; + + private NibbleArray _values; + + public uint Length => _values.Length; + + public Tails(uint length) => _values = new(length); + + public uint this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _values[index]; + + set => _values[index] = value; + } + + public void Reset() => _values.Clear(); //_values.Initialize(15u); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsEmpty(int index) => _values[(uint)index] == EMPTY; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsSolo(int index) => _values[(uint)index] == SOLO; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsSoloOrEmpty(int index) => _values[(uint)index] <= 1u; + + public void SetSolo(int index) => _values[(uint)index] = SOLO; + + public void SetEmpty(int index) => _values[(uint)index] = EMPTY; + } + + public record struct Enumerator : IEnumerator>, IDictionaryEnumerator + { + private readonly FishTable _dictionary; + private readonly int _version; + private uint _index; + private KeyValuePair _current; + private readonly int _getEnumeratorRetType; // What should Enumerator.Current return? + + internal const int DICT_ENTRY = 1; + internal const int KEY_VALUE_PAIR = 2; + + internal Enumerator(FishTable dictionary, int getEnumeratorRetType) + { + _dictionary = dictionary; + _version = dictionary._version; + _index = 0u; + _getEnumeratorRetType = getEnumeratorRetType; + _current = default; + } + + public bool MoveNext() + { + if (_version != _dictionary._version) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); + + while (_index < (uint)_dictionary._buckets.Length) + { + if (_dictionary.IsBucketEmpty((int)_index++)) + continue; + + _current = _dictionary._buckets[_index - 1].AsKeyValuePair()!; + return true; + } + + _index = (uint)_dictionary._buckets.Length + 1u; + _current = default; + return false; + } + + [CollectionAccess(CollectionAccessType.Read)] + public KeyValuePair Current => _current; + + public void Dispose() + { + } + + object IEnumerator.Current + { + get + { + if (_index == 0u || _index == (uint)_dictionary._buckets.Length + 1u) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return _getEnumeratorRetType == DICT_ENTRY + ? new DictionaryEntry(_current.Key!, _current.Value) + : _current; + } + } + + void IEnumerator.Reset() + { + if (_version != _dictionary._version) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); + + _index = 0u; + _current = default; + } + + DictionaryEntry IDictionaryEnumerator.Entry + { + get + { + if (_index == 0u || _index == (uint)_dictionary._buckets.Length + 1u) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return new(_current.Key!, _current.Value); + } + } + + object? IDictionaryEnumerator.Key + { + get + { + if (_index == 0u || _index == (uint)_dictionary._buckets.Length + 1u) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return _current.Key; + } + } + + object? IDictionaryEnumerator.Value + { + get + { + if (_index == 0u || _index == (uint)_dictionary._buckets.Length + 1u) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return _current.Value; + } + } + } + + #endregion + + private static class ThrowHelper + { + [DoesNotReturn] + internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() + => throw new InvalidOperationException("Collection was modified; enumeration operation may not execute."); + + [DoesNotReturn] + internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() + => throw new InvalidOperationException("Enumeration has either not started or has already finished."); + + [DoesNotReturn] + internal static void ThrowKeyNotFoundException(T key) + { + Guard.IsNotNull(key); + ThrowKeyNotFoundException((object)key); + } + + [DoesNotReturn] + private static void ThrowKeyNotFoundException(object key) + => throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary."); + + [DoesNotReturn] + internal static void ThrowWrongValueTypeArgumentException(object value) + => throw new ArgumentException( + $"The value \"{value}\" is not of type \"{ + typeof(TValue)}\" and cannot be used in this generic collection.", + nameof(value)); + + [DoesNotReturn] + internal static void ThrowWrongKeyTypeArgumentException(object? key) + { + Guard.IsNotNull(key); + throw new ArgumentException($"The value \"{key}\" is not of type \"{ + typeof(TKey)}\" and cannot be used in this generic collection.", + nameof(key)); + } + + [DoesNotReturn] + internal static void ThrowAddingDuplicateWithKeyArgumentException(T key) + { + Guard.IsNotNull(key); + ThrowAddingDuplicateWithKeyArgumentException((object)key); + } + + [DoesNotReturn] + internal static void ThrowEmptyBucketKeyInvalidOperationException(int bucketIndex, Entry bucket) + => throw new InvalidOperationException( + $"Bucket marked as empty had non-default key. This should never happen. Index: '{ + bucketIndex}', key: '{bucket.Key}', value: '{bucket.Value}'"); + + [DoesNotReturn] + internal static void ThrowInvalidKeysValuesSizeArgumentException() + => Utility.Diagnostics.ThrowHelper.ThrowArgumentException( + "Input collections have different sizes. AddRange expects a matching Count for keys and values"); + + [DoesNotReturn] + internal static unsafe void ThrowFailedToFindParentInvalidOperationException(FishTable fishTable, + int childBucketIndex) + { + var entry = fishTable._buckets[childBucketIndex]; + throw new InvalidOperationException($"Failed to find parent index in FishTable for key: '{ + entry.Key}', hashCode: '{fishTable._keyHashCodeGetter(entry.Key)}', value: '{entry.Value}', count: '{ + fishTable._count}', bucket array length: '{fishTable._buckets.Length}', tailing entries: '{ + fishTable.GetTailingEntriesCount()}'"); + } + + [DoesNotReturn] + private static void ThrowAddingDuplicateWithKeyArgumentException(object key) + => throw new ArgumentException($"An item with the same key has already been added. Key: {key}"); + } +} +#pragma warning restore CS8766, CS8767 \ No newline at end of file diff --git a/Source/FisheryLib/Collections/NibbleArray.cs b/Source/FisheryLib/Collections/NibbleArray.cs new file mode 100644 index 0000000..4edabf7 --- /dev/null +++ b/Source/FisheryLib/Collections/NibbleArray.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2023 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System.Runtime.CompilerServices; +using JetBrains.Annotations; + +namespace FisheryLib.Collections; + +[PublicAPI] +public struct NibbleArray +{ + private uint _length; + private byte[] _data; + + public uint this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + Guard.IsLessThan(index, _length); + + return (index & 1u) == 0u ? _data[index >> 1] & 0b0000_1111u : (uint)_data[index >> 1] >> 4; + } + set + { + Guard.IsLessThan(value, 16u); + Guard.IsLessThan(index, _length); + + _data[index >> 1] = (byte)((index & 1u) == 0u + ? (_data[index >> 1] & 0b1111_0000u) | value + : (_data[index >> 1] & 0b0000_1111u) | (value << 4)); + } + } + + public uint Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _length; + } + + public NibbleArray(uint length) + { + _length = length; + _data = new byte[(length + 1u) >> 1]; + } + + public void Resize(uint newSize) + { + _length = newSize; + Array.Resize(ref _data, (int)(newSize + 1u) >> 1); + } + + public void Clear() => _data.Clear(); + + public void Initialize(uint value) + { + Guard.IsLessThan(value, 16u); + Unsafe.InitBlockUnaligned(ref _data[0u], (byte)(value | (value << 4)), (uint)_data.Length); + } +} \ No newline at end of file diff --git a/Source/FisheryLib/Collections/StructFishTable.cs b/Source/FisheryLib/Collections/StructFishTable.cs new file mode 100644 index 0000000..d6cd185 --- /dev/null +++ b/Source/FisheryLib/Collections/StructFishTable.cs @@ -0,0 +1,1050 @@ +// Copyright (c) 2023 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// Based on https://github.com/matthewcrews/FastDictionaryTest/tree/main +// which itself is based on +// https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/ + +#if false + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using FisheryLib.FunctionPointers; +using JetBrains.Annotations; + +namespace FisheryLib.Collections; + +#pragma warning disable CS8766, CS8767 +[PublicAPI] +[StructLayout(LayoutKind.Sequential)] +public struct StructFishTable : ICollection + //: IDictionary, IDictionary, IReadOnlyDictionary +{ + private static ReadOnlySpan TrailingZeroCountDeBruijn + => new byte[] + { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, + 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, + 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, + 10, 9 + }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int TrailingZeroCount(uint value) + => value == 0 + ? 32 + : Unsafe.AddByteOffset(ref TrailingZeroCountDeBruijn.DangerousGetPinnableReference(), + (IntPtr)(int)(((value & unchecked(0 - value)) * 125613361) >> 27)); + + internal Entry[] _buckets; + + private unsafe delegate* _keyHashCodeByRefGetter = GetHashCodeByRef.Default; + private unsafe delegate* _keyEqualityByRefComparer = EqualsByRef.Default; + + private int + _bucketBitShift, + _count; + + private unsafe delegate* _keyHashCodeGetter = GetHashCode.Default; + private unsafe delegate* _keyEqualityComparer = Equals.Default; + + private int + _wrapAroundMask, + _version; + + //private KeyCollection _keys; + + //private ValueCollection _values; + + public ICollection Keys => throw new NotImplementedException(); + + public ICollection Values => throw new NotImplementedException(); + + public int Version + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _version; + } + + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _count; + } + + public bool IsReadOnly => false; + + // ICollection IDictionary.Keys => throw new NotImplementedException(); + // + // ICollection IDictionary.Values => throw new NotImplementedException(); + // + // bool IDictionary.IsFixedSize => false; + object ICollection.SyncRoot => this; // matching System.Collections.Generic.Dictionary + bool ICollection.IsSynchronized => false; + // + // IEnumerable IReadOnlyDictionary.Keys => throw new NotImplementedException(); + // + // IEnumerable IReadOnlyDictionary.Values => throw new NotImplementedException(); + // + // object? IDictionary.this[object key] + // { + // get + // => key is TKey tKey + // ? this[tKey] + // : ThrowHelper.ThrowKeyNotFoundException(key); + // + // set + // { + // if (key is TKey tKey) + // { + // switch (value) + // { + // case TValue tValue: + // this[tKey] = tValue; + // break; + // case null: + // this[tKey] = default; + // break; + // default: + // ThrowHelper.ThrowWrongValueTypeArgumentException(value); + // break; + // } + // } + // else + // { + // ThrowHelper.ThrowWrongKeyTypeArgumentException(key); + // } + // } + // } + + public unsafe TValue? this[TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + return entry.Value; + + if (entry.IsLast) + ThrowHelper.ThrowKeyNotFoundException(key); + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + set + { + AddEntry(key, value); + Resize(); + } + } + + public StructFishTable() : this(0) + { + } + + public StructFishTable(int minimumCapacity) => Initialize(minimumCapacity); + + [MemberNotNull(nameof(_buckets))] + private void Initialize(int minimumCapacity = 0) + { + //_buckets = new Entry[minimumCapacity <= 1 ? 1 : Mathf.NextPowerOfTwo(minimumCapacity)]; + + _buckets = new Entry[4]; + for (var i = 0; i < _buckets.Length; i++) + _buckets[i].Next = byte.MaxValue; + + _bucketBitShift = 32 - TrailingZeroCount((uint)_buckets.Length); + _wrapAroundMask = _buckets.Length - 1; + } + + public StructFishTable(IEnumerable> entries) : this(0) + { + foreach (var entry in entries) + { + AddEntry(entry.Key, entry.Value); + Resize(); + } + } + + private void SetNextEntryIndex(ref int entryIndex, byte next) => entryIndex = GetNextEntryIndex(entryIndex, next); + + private int GetNextEntryIndex(int entryIndex, byte next) => (entryIndex + next /*GetJumpDistance(next)*/) & _wrapAroundMask; + + // private static long GetJumpDistanceLong(byte index) + // => index switch + // { + // 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, + // 8 => 8, 9 => 9, 10 => 10, 11 => 11, 12 => 12, 13 => 13, 14 => 14, + // 15 => 15, 16 => 21, 17 => 28, 18 => 36, 19 => 45, 20 => 55, 21 => 66, + // 22 => 78, 23 => 91, 24 => 105, 25 => 120, 26 => 136, 27 => 153, + // 28 => 171, 29 => 190, 30 => 210, 31 => 231, 32 => 253, 33 => 276, + // 34 => 300, 35 => 325, 36 => 351, 37 => 378, 38 => 406, 39 => 435, + // 40 => 465, 41 => 496, 42 => 528, 43 => 561, 44 => 595, 45 => 630, + // 46 => 666, 47 => 703, 48 => 741, 49 => 780, 50 => 820, 51 => 861, + // 52 => 903, 53 => 946, 54 => 990, 55 => 1035, 56 => 1081, 57 => 1128, + // 58 => 1176, 59 => 1225, 60 => 1275, 61 => 1326, 62 => 1378, 63 => 1431, + // 64 => 1485, 65 => 1540, 66 => 1596, 67 => 1653, 68 => 1711, 69 => 1770, + // 70 => 1830, 71 => 1891, 72 => 1953, 73 => 2016, 74 => 2080, 75 => 2145, + // 76 => 2211, 77 => 2278, 78 => 2346, 79 => 2415, 80 => 2485, 81 => 2556, + // 82 => 3741, 83 => 8385, 84 => 18915, 85 => 42486, 86 => 95703, 87 => 215496, + // 88 => 485605, 89 => 1091503, 90 => 2456436, 91 => 5529475, 92 => 12437578, + // 93 => 27986421, 94 => 62972253, 95 => 141700195, 96 => 318819126, 97 => 717314626, + // 98 => 1614000520, 99 => 3631437253, 100 => 8170829695, 101 => 18384318876, 102 => 41364501751, + // 103 => 93070021080, 104 => 209407709220, 105 => 471167588430, 106 => 1060127437995, 107 => 2385287281530, + // 108 => 5366895564381, 109 => 12075513791265, 110 => 27169907873235, 111 => 61132301007778, + // 112 => 137547673121001, 113 => 309482258302503, 114 => 696335090510256, 115 => 1566753939653640, + // 116 => 3525196427195653, 117 => 7931691866727775, 118 => 17846306747368716, + // 119 => 40154190394120111, 120 => 90346928493040500, 121 => 203280588949935750, + // 122 => 457381324898247375, 123 => 1029107980662394500, 124 => 2315492957028380766, + // 125 => 5209859150892887590, > 125 => throw new() + // }; + + // private static int GetJumpDistance(byte index) + // => index switch + // { + // 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 10, 11 => 11, + // 12 => 12, 13 => 13, 14 => 14, 15 => 15, 16 => 21, 17 => 28, 18 => 36, 19 => 45, 20 => 55, 21 => 66, + // 22 => 78, 23 => 91, 24 => 105, 25 => 120, 26 => 136, 27 => 153, 28 => 171, 29 => 190, 30 => 210, 31 => 231, + // 32 => 253, 33 => 276, 34 => 300, 35 => 325, 36 => 351, 37 => 378, 38 => 406, 39 => 435, 40 => 465, + // 41 => 496, 42 => 528, 43 => 561, 44 => 595, 45 => 630, 46 => 666, 47 => 703, 48 => 741, 49 => 780, + // 50 => 820, 51 => 861, 52 => 903, 53 => 946, 54 => 990, 55 => 1035, 56 => 1081, 57 => 1128, 58 => 1176, + // 59 => 1225, 60 => 1275, 61 => 1326, 62 => 1378, 63 => 1431, 64 => 1485, 65 => 1540, 66 => 1596, 67 => 1653, + // 68 => 1711, 69 => 1770, 70 => 1830, 71 => 1891, 72 => 1953, 73 => 2016, 74 => 2080, 75 => 2145, 76 => 2211, + // 77 => 2278, 78 => 2346, 79 => 2415, 80 => 2485, 81 => 2556, 82 => 3741, 83 => 8385, 84 => 18915, + // 85 => 42486, 86 => 95703, 87 => 215496, 88 => 485605, 89 => 1091503, 90 => 2456436, 91 => 5529475, + // 92 => 12437578, 93 => 27986421, 94 => 62972253, 95 => 141700195, 96 => 318819126, 97 => 717314626, + // 98 => 1614000520, 255 => int.MaxValue, > 98 => ThrowForInvalidIndex(index) + // }; + + private static int ThrowForInvalidIndex(byte index) + => throw new($"Jump distance index for FishTable too large. Should be < 99, got {index} instead."); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int ComputeBucketIndex(int hashCode) => (hashCode * -1640531527) >>> _bucketBitShift; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe bool IsTail(int bucketIndex) + => bucketIndex != ComputeBucketIndex(_keyHashCodeGetter(_buckets[bucketIndex].Key)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetParentBucketIndex(int hashCode, int childBucketIndex) + { + var ancestorIndex = ComputeBucketIndex(hashCode); + while (true) + { + var nextIndex = GetNextEntryIndex(ancestorIndex, _buckets[ancestorIndex].Next); + if (nextIndex == childBucketIndex) + break; + + ancestorIndex = nextIndex; + } + return ancestorIndex; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe byte DistanceFromParent(int bucketIndex) + => _buckets[GetParentBucketIndex(_keyHashCodeGetter(_buckets[bucketIndex].Key), bucketIndex)].Next; + + private void SetEntry(byte next, int hashCode, TKey key, TValue? value, int bucketIndex) + { + ref var entry = ref _buckets[bucketIndex]; + entry.Next = next; + entry.Key = key; + entry.Value = value; + } + + private unsafe void RemoveFromList(int entryIndex) + { + ref var entry = ref _buckets[entryIndex]; + var parentEntryIndex = GetParentBucketIndex(_keyHashCodeGetter(entry.Key), entryIndex); + + _buckets[parentEntryIndex].Next + = entry.IsLast ? (byte)0 : (byte)(_buckets[parentEntryIndex].Next + entry.Next); + } + + private unsafe void AddEntry(TKey key, TValue? value) => AddEntry(_keyHashCodeGetter(key), key, value); + + private unsafe void AddEntry(int hashCode, TKey key, TValue? value) + { + _version++; + + var entryIndex = ComputeBucketIndex(hashCode); + ref var entry = ref _buckets[entryIndex]; + if (entry.IsAvailable) + { + SetEntry(0, hashCode, key, value, entryIndex); + _count++; + } + else if (_keyHashCodeGetter(entry.Key) == hashCode && _keyEqualityComparer(entry.Key, key)) + { + entry.Value = value; + } + else if (IsTail(entryIndex)) + { + var previousEntry = _buckets[entryIndex]; + RemoveFromList(entryIndex); + SetEntry(0, hashCode, key, value, entryIndex); + AddEntry(_keyHashCodeGetter(previousEntry.Key), previousEntry.Key, previousEntry.Value); + _count++; + } + else + { + ListSearch(hashCode, key, value, entryIndex); + } + } + + private unsafe void ListSearch(int hashCode, TKey key, TValue? value, int bucketIndex) + { + while (true) + { + ref var bucket = ref _buckets[bucketIndex]; + if (_keyHashCodeGetter(bucket.Key) == hashCode && _keyEqualityComparer(bucket.Key, key)) + { + bucket.Value = value; + return; + } + if (bucket.IsLast | bucket.IsEmpty) + break; + + SetNextEntryIndex(ref bucketIndex, bucket.Next); + } + InsertIntoNextEmptyBucket(bucketIndex, hashCode, key, value, 1, bucketIndex + 1); + } + + private unsafe void InsertIntoNextEmptyBucket(int parentIndex, int hashCode, TKey key, TValue? value, byte offset, int bucketIndex) + { + while (true) + { + if (bucketIndex < _buckets.Length) + { + if (_buckets[bucketIndex].IsAvailable) + { + SetEntry(0, hashCode, key, value, bucketIndex); + _count++; + _buckets[parentIndex].Next = offset; + return; + } + if (IsTail(bucketIndex) && (uint)offset > DistanceFromParent(bucketIndex)) + break; + + bucketIndex++; + offset++; + } + else + { + bucketIndex = 0; + } + } + var previousEntry = _buckets[bucketIndex]; + RemoveFromList(bucketIndex); + SetEntry(0, hashCode, key, value, bucketIndex); + _buckets[parentIndex].Next = offset; + AddEntry(_keyHashCodeGetter(previousEntry.Key), previousEntry.Key, previousEntry.Value); + } + + private void Resize() + { + if (_count <= (_buckets.Length >> 2) * 3) + return; + var oldBuckets = _buckets; + + _buckets = new Entry[_buckets.Length << 1]; + for (var i = 0; i < _buckets.Length; i++) + _buckets[i].Next = byte.MaxValue; + + _bucketBitShift = 64 - TrailingZeroCount((uint)_buckets.Length); + _wrapAroundMask = _buckets.Length - 1; + _count = 0; + for (var i = 0; i < oldBuckets.Length; i++) + { + var bucket = oldBuckets[i]; + if (bucket.IsEntry) + AddEntry(bucket.Key, bucket.Value); + } + } + + public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + { + value = entry.Value!; + return true; + } + + if (entry.IsLast | entry.IsEmpty) + { + value = default; + return false; + } + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + + public unsafe TValue? TryGetValue(TKey key) + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + return entry.Value; + + if (entry.IsLast | entry.IsEmpty) + return default; + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + + public unsafe TValue GetOrAdd(TKey key) + { + while (true) + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + return entry.Value!; + + if (entry.IsLast | entry.IsEmpty) + { + this[key] = Reflection.New(); + break; + } + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + } + + public unsafe TValue GetOrAdd(ref TKey key) + { + while (true) + { + var hashCode = _keyHashCodeByRefGetter(ref key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeByRefGetter(ref entry.Key)) & _keyEqualityByRefComparer(ref key, ref entry.Key)) + return entry.Value!; + + if (entry.IsLast | entry.IsEmpty) + { + this[key] = Reflection.New(); + break; + } + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + } + + public unsafe ref TValue GetOrAddReference(TKey key) + { + while (true) + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + return ref entry.Value!; + + if (entry.IsLast | entry.IsEmpty) + { + this[key] = Reflection.New(); + break; + } + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + } + + public unsafe ref TValue GetOrAddReference(ref TKey key) + { + while (true) + { + var hashCode = _keyHashCodeByRefGetter(ref key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeByRefGetter(ref entry.Key)) + & _keyEqualityByRefComparer(ref key, ref entry.Key)) + { + return ref entry.Value!; + } + + if (entry.IsLast | entry.IsEmpty) + { + this[key] = Reflection.New(); + break; + } + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + } + + public unsafe ref TValue GetReference(TKey key) + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + return ref entry.Value!; + + if (entry.IsLast | entry.IsEmpty) + ThrowHelper.ThrowKeyNotFoundException(key); + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + + public unsafe ref TValue GetReference(ref TKey key) + { + var hashCode = _keyHashCodeByRefGetter(ref key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeByRefGetter(ref entry.Key)) & _keyEqualityByRefComparer(ref key, ref entry.Key)) + return ref entry.Value!; + + if (entry.IsLast | entry.IsEmpty) + ThrowHelper.ThrowKeyNotFoundException(key); + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + + /// + /// Returns a reference to the value field of an entry if the key exists and an Unsafe.NullRef{TValue} if not. + /// Must be checked with Unsafe.IsNullRef before assigning to a regular var or field without ref. + /// + /// The key + /// ref TValue or Unsafe.NullRef{TValue} + public unsafe ref TValue? TryGetReferenceUnsafe(TKey key) + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + return ref entry.Value; + + if (entry.IsLast | entry.IsEmpty) + return ref Unsafe.NullRef(); + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + + public unsafe ref TValue? TryGetReferenceUnsafe(ref TKey key) + { + var hashCode = _keyHashCodeByRefGetter(ref key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeByRefGetter(ref entry.Key)) + & _keyEqualityByRefComparer(ref key, ref entry.Key)) + { + return ref entry.Value; + } + + if (entry.IsLast | entry.IsEmpty) + return ref Unsafe.NullRef(); + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + + public unsafe bool ContainsKey(TKey key) + { + var hashCode = _keyHashCodeGetter(key); + var entryIndex = ComputeBucketIndex(hashCode); + + while (true) + { + ref var entry = ref _buckets[entryIndex]; + + if ((hashCode == _keyHashCodeGetter(entry.Key)) & _keyEqualityComparer(key, entry.Key)) + return true; + + if (entry.IsLast | entry.IsEmpty) + return false; + + SetNextEntryIndex(ref entryIndex, entry.Next); + } + } + +#if false + public void Add(TKey key, TValue value) + { + Guard.IsNotNull(key); + + if ( + _count + == _buckets.Length) // throwing DuplicateKeyExceptions happens later, so Expanding occurs based on expected + Expand(); // behaviour instead of matching actual results like in System.Collections.Generic. + + var keyCode = (uint)HashCode.Get(key); + ref var entry = ref _buckets[FastModulo(keyCode, (uint)_buckets.Length)]; + + while (entry.Next != null) + { + if (entry.HashCode == keyCode && entry.Key.Equals(key)) + ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key); + + if (entry.Next == EntryReference.Empty) + break; + + entry = ref entry.Next.Entry; + } + + if (entry.Next == null) // means the entry is empty + entry = new(keyCode, key, value); + else // if (entry.Next == _freeSlot) // occupied entry with an empty slot in entry.Next + entry.Next = new(keyCode, key, value); + // entry.Next != _freeSlot would be a threading issue, as this was just checked in the loop. Unhandled. + + _count++; + _version++; + } + + private void Expand() + { + var newLength = Mathf.NextPowerOfTwo(_buckets.Length + 1); + var newArray = new Entry[newLength]; + + for (var i = 0; i < _buckets.Length; i++) + { + var entry = _buckets[i]; + + var nextEntry = entry.Next; + if (nextEntry is null) + continue; + + BeforeAdding: + ref var newEntry = ref newArray[FastModulo(entry.HashCode, (uint)newLength)]; + + while (newEntry.Next != null) + { + if (newEntry.HashCode == entry.HashCode && newEntry.Key.Equals(entry.Key)) + ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(entry.Key); + + if (newEntry.Next == EntryReference.Empty) + break; + + newEntry = ref newEntry.Next.Entry; + } + + entry.Next = EntryReference.Empty; + + if (newEntry.Next == null) + newEntry = entry; + else + newEntry.Next = new(entry); + + if (nextEntry != EntryReference.Empty) + { + entry = nextEntry.Entry; + goto BeforeAdding; + } + } + + _buckets = newArray; + } + + private ref Entry TryFindEntry(TKey key) + { + var keyCode = (uint)HashCode.Get(key); + ref var entry = ref _buckets[FastModulo(keyCode, (uint)_buckets.Length)]; + + while (entry.HashCode != keyCode || !entry.Key.Equals(key)) + { + if (entry.Next != EntryReference.Empty && entry.Next != null) + entry = ref entry.Next.Entry; + else + return ref Unsafe.NullRef(); + } + + return ref entry; + } + + private void RemoveEntry(ref Entry entry) + { + entry = entry.Next != EntryReference.Empty && entry.Next != null + ? entry.Next.Entry + : default; + + _count--; + _version++; + } + + public bool Remove(TKey key) + { + ref var entry = ref TryFindEntry(key); + if (Unsafe.IsNullRef(ref entry)) + return false; + + RemoveEntry(ref entry); + return true; + } + + public void Add(KeyValuePair item) => Add(item.Key, item.Value); +#endif + + public void Clear() + { + if (_buckets is null) + Initialize(); + + Array.Clear(_buckets, 0, _buckets.Length); + for (var i = 0; i < _buckets.Length; i++) + _buckets[i].Next = byte.MaxValue; + + _count = 0; + _version++; + } + + public bool Contains(KeyValuePair item) + => TryGetValue(item.Key, out var value) + && value.Equals(item.Value); + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + var length = _buckets.Length; + for (var i = 0; i < length; i++) + { + ref var entry = ref _buckets[i]; + if (entry.IsEmpty) + continue; + + array[arrayIndex] = new(entry.Key, entry.Value!); + arrayIndex++; + } + } + +#if false + public bool Remove(KeyValuePair item) + { + ref var entry = ref TryFindEntry(item.Key); + + if (Unsafe.IsNullRef(ref entry) + || !entry.Value.Equals(item.Value)) + { + return false; + } + + RemoveEntry(ref entry); + return true; + } +#endif + + public Enumerator GetEnumerator() => new(this, Enumerator.KEY_VALUE_PAIR); + + // IEnumerator> IEnumerable>.GetEnumerator() + // => new Enumerator(this, Enumerator.KEY_VALUE_PAIR); + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this, Enumerator.KEY_VALUE_PAIR); + +#if false + bool IDictionary.Contains(object key) + { + Guard.IsNotNull(key); + + return key is TKey tkey + && ContainsKey(tkey); + } + + void IDictionary.Add(object key, object value) => throw new NotImplementedException(); + + //IDictionaryEnumerator IDictionary.GetEnumerator() => new Enumerator(this, Enumerator.DICT_ENTRY); + + void IDictionary.Remove(object key) + { + Guard.IsNotNull(key); + + if (key is TKey tkey) + Remove(tkey); + } +#endif + + void ICollection.CopyTo(Array array, int index) + { + if (array is KeyValuePair[] typedArray) + { + CopyTo(typedArray, index); + return; + } + + var length = _buckets.Length; + for (var i = 0; i < length; i++) + { + ref var entry = ref _buckets[i]; + if (entry.IsEmpty) + continue; + + ((IList)array)[index] = new KeyValuePair(entry.Key, entry.Value!); + index++; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct Entry + { + public byte Next; + public TKey Key; + public TValue? Value; + + internal bool IsTombstone + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Next == 254; + } + + internal bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Next == byte.MaxValue; + } + + internal bool IsEntry + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Next < 254u; + } + + internal bool IsOccupied + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Next <= 254u; + } + + internal bool IsAvailable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Next >= 254u; + } + + internal bool IsLast + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Next == 0; + } + } + + public record struct Enumerator : IEnumerator>, IDictionaryEnumerator + { + private readonly StructFishTable _dictionary; + private readonly int _version; + private int _index; + private KeyValuePair _current; + private readonly int _getEnumeratorRetType; // What should Enumerator.Current return? + + internal const int DICT_ENTRY = 1; + internal const int KEY_VALUE_PAIR = 2; + + internal Enumerator(StructFishTable dictionary, int getEnumeratorRetType) + { + _dictionary = dictionary; + _version = dictionary._version; + _index = 0; + _getEnumeratorRetType = getEnumeratorRetType; + _current = default; + } + + public bool MoveNext() + { + if (_version != _dictionary._version) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); + + // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends. + // dictionary.count+1 could be negative if dictionary.count is int.MaxValue + while ((uint)_index < (uint)_dictionary._buckets.Length) + { + ref var entry = ref _dictionary._buckets[_index++]; + + if (entry.IsEmpty) + continue; + + _current = new(entry.Key, entry.Value!); + return true; + } + + _index = _dictionary._buckets.Length + 1; + _current = default; + return false; + } + + public KeyValuePair Current => _current; + + public void Dispose() + { + } + + object IEnumerator.Current + { + get + { + if (_index == 0 || _index == _dictionary._buckets.Length + 1) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return _getEnumeratorRetType == DICT_ENTRY + ? new DictionaryEntry(_current.Key!, _current.Value) + : new KeyValuePair(_current.Key, _current.Value); + } + } + + void IEnumerator.Reset() + { + if (_version != _dictionary._version) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); + + _index = 0; + _current = default; + } + + DictionaryEntry IDictionaryEnumerator.Entry + { + get + { + if (_index == 0 || _index == _dictionary._buckets.Length + 1) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return new(_current.Key!, _current.Value); + } + } + + object? IDictionaryEnumerator.Key + { + get + { + if (_index == 0 || _index == _dictionary._buckets.Length + 1) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return _current.Key; + } + } + + object? IDictionaryEnumerator.Value + { + get + { + if (_index == 0 || _index == _dictionary._buckets.Length + 1) + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + + return _current.Value; + } + } + } + + private static class ThrowHelper + { + [DoesNotReturn] + internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() + => throw new InvalidOperationException("Collection was modified; enumeration operation may not execute."); + + [DoesNotReturn] + internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() + => throw new InvalidOperationException("Enumeration has either not started or has already finished."); + + [DoesNotReturn] + internal static void ThrowKeyNotFoundException(T key) + { + Guard.IsNotNull(key); + ThrowKeyNotFoundException((object)key); + } + + [DoesNotReturn] + internal static V ThrowKeyNotFoundException(T key) + { + Guard.IsNotNull(key); + ThrowKeyNotFoundException((object)key); + return default; + } + + [DoesNotReturn] + private static void ThrowKeyNotFoundException(object key) + => throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary."); + + [DoesNotReturn] + internal static void ThrowWrongValueTypeArgumentException(object value) + => throw new ArgumentException( + $"The value \"{value}\" is not of type \"{ + typeof(TValue)}\" and cannot be used in this generic collection.", + nameof(value)); + + [DoesNotReturn] + internal static void ThrowWrongKeyTypeArgumentException(object? key) + { + Guard.IsNotNull(key); + throw new ArgumentException($"The value \"{key}\" is not of type \"{ + typeof(TKey)}\" and cannot be used in this generic collection.", + nameof(key)); + } + + [DoesNotReturn] + internal static void ThrowAddingDuplicateWithKeyArgumentException(T key) + { + Guard.IsNotNull(key); + ThrowAddingDuplicateWithKeyArgumentException((object)key); + } + + [DoesNotReturn] + private static void ThrowAddingDuplicateWithKeyArgumentException(object key) + => throw new ArgumentException($"An item with the same key has already been added. Key: {key}"); + } +} + +#pragma warning restore CS8766, CS8767 + +#endif \ No newline at end of file diff --git a/Source/FisheryLib/Convert.cs b/Source/FisheryLib/Convert.cs index fe164e9..0c5f9f0 100644 --- a/Source/FisheryLib/Convert.cs +++ b/Source/FisheryLib/Convert.cs @@ -7,23 +7,23 @@ using System.Globalization; using System.Runtime.CompilerServices; namespace FisheryLib; + public static class Convert { [Obsolete("Renamed to Convert.Type for clarity")] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe TTo To(TFrom from) where TFrom : IConvertible - => Type(from); + public static TTo To(TFrom from) => Type(from); [Obsolete("Renamed to Convert.Type for clarity")] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe TTo To(TFrom from, IFormatProvider provider) where TFrom : IConvertible + public static TTo To(TFrom from, IFormatProvider provider) => Type(from, provider); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe TTo Type(TFrom from) where TFrom : IConvertible + public static unsafe TTo Type(TFrom from) => FunctionPointers.Convert.To.Default(from, CultureInfo.InvariantCulture); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe TTo Type(TFrom from, IFormatProvider provider) where TFrom : IConvertible + public static unsafe TTo Type(TFrom from, IFormatProvider provider) => FunctionPointers.Convert.To.Default(from, provider); } \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Attributes/UnscopedRefAttribute.cs b/Source/FisheryLib/Diagnostics/Attributes/UnscopedRefAttribute.cs new file mode 100644 index 0000000..3665d18 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Attributes/UnscopedRefAttribute.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Diagnostics.CodeAnalysis; + +/// +/// Used to indicate a byref escapes and is not scoped. +/// +/// +/// +/// There are several cases where the C# compiler treats a as implicitly +/// - where the compiler does not allow the to escape the method. +/// +/// +/// For example: +/// +/// for instance methods. +/// parameters that refer to types. +/// parameters. +/// +/// +/// +/// This attribute is used in those instances where the should be allowed to escape. +/// +/// +/// Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for +/// API authors to understand the lifetime implications of applying this attribute and how it may impact their users. +/// +/// +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, + Inherited = false)] +internal sealed class UnscopedRefAttribute : Attribute +{ + /// + /// Initializes a new instance of the class. + /// + public UnscopedRefAttribute() { } +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Extensions/TypeExtensions.cs b/Source/FisheryLib/Diagnostics/Extensions/TypeExtensions.cs index aacaa23..ee06ed7 100644 --- a/Source/FisheryLib/Diagnostics/Extensions/TypeExtensions.cs +++ b/Source/FisheryLib/Diagnostics/Extensions/TypeExtensions.cs @@ -52,9 +52,7 @@ public static class TypeExtensions { // Primitive types use the keyword name if (BuiltInTypesMap.TryGetValue(type, out var typeName)) - { return typeName!; - } // Array types are displayed as Foo[] if (type.IsArray) @@ -62,7 +60,8 @@ public static class TypeExtensions var elementType = type.GetElementType()!; var rank = type.GetArrayRank(); - return $"{FormatDisplayString(elementType, 0, elementType.GetGenericArguments())}[{new string(',', rank - 1)}]"; + return $"{FormatDisplayString(elementType, 0, + elementType.GetGenericArguments())}[{new string(',', rank - 1)}]"; } // By checking generic types here we are only interested in specific cases, @@ -84,16 +83,17 @@ public static class TypeExtensions } // ValueTuple types are displayed as (T1, T2) - if (genericTypeDefinition == typeof(ValueTuple<>) || - genericTypeDefinition == typeof(ValueTuple<,>) || - genericTypeDefinition == typeof(ValueTuple<,,>) || - genericTypeDefinition == typeof(ValueTuple<,,,>) || - genericTypeDefinition == typeof(ValueTuple<,,,,>) || - genericTypeDefinition == typeof(ValueTuple<,,,,,>) || - genericTypeDefinition == typeof(ValueTuple<,,,,,,>) || - genericTypeDefinition == typeof(ValueTuple<,,,,,,,>)) + if (genericTypeDefinition == typeof(ValueTuple<>) + || genericTypeDefinition == typeof(ValueTuple<,>) + || genericTypeDefinition == typeof(ValueTuple<,,>) + || genericTypeDefinition == typeof(ValueTuple<,,,>) + || genericTypeDefinition == typeof(ValueTuple<,,,,>) + || genericTypeDefinition == typeof(ValueTuple<,,,,,>) + || genericTypeDefinition == typeof(ValueTuple<,,,,,,>) + || genericTypeDefinition == typeof(ValueTuple<,,,,,,,>)) { - var formattedTypes = type.GetGenericArguments().Select(t => FormatDisplayString(t, 0, t.GetGenericArguments())); + var formattedTypes = type.GetGenericArguments() + .Select(static t => FormatDisplayString(t, 0, t.GetGenericArguments())); return $"({string.Join(", ", formattedTypes)})"; } @@ -109,7 +109,8 @@ public static class TypeExtensions var genericArgumentsCount = int.Parse(tokens[1]); var typeArgumentsOffset = typeArguments.Length - genericTypeOffset - genericArgumentsCount; var currentTypeArguments = typeArguments.Slice(typeArgumentsOffset, genericArgumentsCount).ToArray(); - var formattedTypes = currentTypeArguments.Select(t => FormatDisplayString(t, 0, t.GetGenericArguments())); + var formattedTypes + = currentTypeArguments.Select(static t => FormatDisplayString(t, 0, t.GetGenericArguments())); // Standard generic types are displayed as Foo displayName = $"{tokens[0]}<{string.Join(", ", formattedTypes)}>"; @@ -130,7 +131,7 @@ public static class TypeExtensions } // Atomically get or build the display string for the current type. - return DisplayNames.GetValue(type, t => + return DisplayNames.GetValue(type, static t => { // By-ref types are displayed as T& if (t.IsByRef) @@ -159,4 +160,4 @@ public static class TypeExtensions return FormatDisplayString(t, 0, t.GetGenericArguments()); }); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Extensions/ValueTypeExtensions.cs b/Source/FisheryLib/Diagnostics/Extensions/ValueTypeExtensions.cs index 54511d9..0201060 100644 --- a/Source/FisheryLib/Diagnostics/Extensions/ValueTypeExtensions.cs +++ b/Source/FisheryLib/Diagnostics/Extensions/ValueTypeExtensions.cs @@ -14,13 +14,8 @@ public static class ValueTypeExtensions /// /// Gets the table of hex characters (doesn't allocate, maps to .text section, see ). /// - private static ReadOnlySpan HexCharactersTable => new[] - { - (byte)'0', (byte)'1', (byte)'2', (byte)'3', - (byte)'4', (byte)'5', (byte)'6', (byte)'7', - (byte)'8', (byte)'9', (byte)'A', (byte)'B', - (byte)'C', (byte)'D', (byte)'E', (byte)'F' - }; + private static ReadOnlySpan HexCharactersTable + => "0123456789ABCDEF"u8; /// /// Returns a hexadecimal representation of a given value, left-padded and ordered as big-endian. @@ -42,7 +37,7 @@ public static class ValueTypeExtensions public static unsafe string ToHexString(this T value) where T : unmanaged { - var sizeOfT = Unsafe.SizeOf(); + var sizeOfT = sizeof(T); var bufferSize = (2 * sizeOfT) + 2; var p = stackalloc char[bufferSize]; @@ -63,4 +58,4 @@ public static class ValueTypeExtensions return new(p, 0, bufferSize); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.tt b/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.tt index 4784e18..6b230cb 100644 --- a/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.tt +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.tt @@ -10,287 +10,287 @@ namespace PerformanceFish.Utility.Diagnostics; partial class Guard { <# -GenerateTextForItems(EnumerableTypes, item => -{ + GenerateTextForItems(EnumerableTypes, item => + { #> /// - /// Asserts that the input <#=item.XmlType#> instance must be empty. + /// Asserts that the input <#= item.XmlType #> instance must be empty. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The name of the input parameter being tested. - /// Thrown if the size of is != 0. + /// Thrown if the size of is != 0. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsEmpty(<#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void IsEmpty(<#= item.Type #> <#= item.Name #>, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> == 0) + if (<#= item.Name #>.<#= item.Size #> == 0) { return; } - ThrowHelper.ThrowArgumentExceptionForIsEmpty(<#=item.Cast#><#=item.Name#>, name); + ThrowHelper.ThrowArgumentExceptionForIsEmpty(<#= item.Cast #><#= item.Name #>, name); } /// - /// Asserts that the input <#=item.XmlType#> instance must not be empty. + /// Asserts that the input <#= item.XmlType #> instance must not be empty. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The name of the input parameter being tested. - /// Thrown if the size of is == 0. + /// Thrown if the size of is == 0. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotEmpty(<#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void IsNotEmpty(<#= item.Type #> <#= item.Name #>, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> != 0) + if (<#= item.Name #>.<#= item.Size #> != 0) { return; } <# -if (item.Type == "Span") -{ + if (item.Type == "Span") + { #> ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithSpan(name); <# -} -else if (item.Type == "ReadOnlySpan") -{ + } + else if (item.Type == "ReadOnlySpan") + { #> ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan(name); <# -} -else -{ + } + else + { #> - ThrowHelper.ThrowArgumentExceptionForIsNotEmpty<<#=item.Type#>>(name); + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty<<#= item.Type #>>(name); <# -} + } #> } /// - /// Asserts that the input <#=item.XmlType#> instance must have a size of a specified value. + /// Asserts that the input <#= item.XmlType #> instance must have a size of a specified value. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The target size to test. /// The name of the input parameter being tested. - /// Thrown if the size of is != . + /// Thrown if the size of is != . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void HasSizeEqualTo(<#= item.Type #> <#= item.Name #>, int size, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> == size) + if (<#= item.Name #>.<#= item.Size #> == size) { return; } - ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#= item.Cast #><#= item.Name #>, size, name); } /// - /// Asserts that the input <#=item.XmlType#> instance must have a size not equal to a specified value. + /// Asserts that the input <#= item.XmlType #> instance must have a size not equal to a specified value. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The target size to test. /// The name of the input parameter being tested. - /// Thrown if the size of is == . + /// Thrown if the size of is == . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeNotEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void HasSizeNotEqualTo(<#= item.Type #> <#= item.Name #>, int size, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> != size) + if (<#= item.Name #>.<#= item.Size #> != size) { return; } - ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(<#= item.Cast #><#= item.Name #>, size, name); } /// - /// Asserts that the input <#=item.XmlType#> instance must have a size over a specified value. + /// Asserts that the input <#= item.XmlType #> instance must have a size over a specified value. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The target size to test. /// The name of the input parameter being tested. - /// Thrown if the size of is <= . + /// Thrown if the size of is <= . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeGreaterThan(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void HasSizeGreaterThan(<#= item.Type #> <#= item.Name #>, int size, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> > size) + if (<#= item.Name #>.<#= item.Size #> > size) { return; } - ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(<#=item.Cast#><#=item.Name#>, size, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(<#= item.Cast #><#= item.Name #>, size, name); } /// - /// Asserts that the input <#=item.XmlType#> instance must have a size of at least or equal to a specified value. + /// Asserts that the input <#= item.XmlType #> instance must have a size of at least or equal to a specified value. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The target size to test. /// The name of the input parameter being tested. - /// Thrown if the size of is < . + /// Thrown if the size of is < . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeGreaterThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void HasSizeGreaterThanOrEqualTo(<#= item.Type #> <#= item.Name #>, int size, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> >= size) + if (<#= item.Name #>.<#= item.Size #> >= size) { return; } - ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(<#= item.Cast #><#= item.Name #>, size, name); } /// - /// Asserts that the input <#=item.XmlType#> instance must have a size of less than a specified value. + /// Asserts that the input <#= item.XmlType #> instance must have a size of less than a specified value. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The target size to test. /// The name of the input parameter being tested. - /// Thrown if the size of is >= . + /// Thrown if the size of is >= . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeLessThan(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void HasSizeLessThan(<#= item.Type #> <#= item.Name #>, int size, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> < size) + if (<#= item.Name #>.<#= item.Size #> < size) { return; } - ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(<#=item.Cast#><#=item.Name#>, size, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(<#= item.Cast #><#= item.Name #>, size, name); } /// - /// Asserts that the input <#=item.XmlType#> instance must have a size of less than or equal to a specified value. + /// Asserts that the input <#= item.XmlType #> instance must have a size of less than or equal to a specified value. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The input <#= item.XmlType #> instance to check the size for. /// The target size to test. /// The name of the input parameter being tested. - /// Thrown if the size of is > . + /// Thrown if the size of is > . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeLessThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + public static void HasSizeLessThanOrEqualTo(<#= item.Type #> <#= item.Name #>, int size, [CallerArgumentExpression("<#= item.Name #>")] string name = "") { - if (<#=item.Name#>.<#=item.Size#> <= size) + if (<#= item.Name #>.<#= item.Size #> <= size) { return; } - ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#= item.Cast #><#= item.Name #>, size, name); } /// - /// Asserts that the source <#=item.XmlType#> instance must have the same size of a destination <#=item.XmlType#> instance. + /// Asserts that the source <#= item.XmlType #> instance must have the same size of a destination <#= item.XmlType #> instance. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The source <#=item.XmlType#> instance to check the size for. - /// The destination <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The source <#= item.XmlType #> instance to check the size for. + /// The destination <#= item.XmlType #> instance to check the size for. /// The name of the input parameter being tested. /// Thrown if the size of is != the one of . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, [CallerArgumentExpression("source")] string name = "") + public static void HasSizeEqualTo(<#= item.Type #> source, <#= item.DestinationType #> destination, [CallerArgumentExpression("source")] string name = "") { - if (source.<#=item.Size#> == destination.<#=item.Size#>) + if (source.<#= item.Size #> == destination.<#= item.Size #>) { return; } <# -if (item.HasCountProperty) -{ + if (item.HasCountProperty) + { #> - ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Cast#>source, destination.<#=item.Size#>, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#= item.Cast #>source, destination.<#= item.Size #>, name); <# -} -else -{ + } + else + { #> - ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, <#=item.Cast#>destination, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, <#= item.Cast #>destination, name); <# -} + } #> } /// - /// Asserts that the source <#=item.XmlType#> instance must have a size of less than or equal to that of a destination <#=item.XmlType#> instance. + /// Asserts that the source <#= item.XmlType #> instance must have a size of less than or equal to that of a destination <#= item.XmlType #> instance. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The source <#=item.XmlType#> instance to check the size for. - /// The destination <#=item.XmlType#> instance to check the size for. + /// The item of items in the input <#= item.XmlType #> instance. + /// The source <#= item.XmlType #> instance to check the size for. + /// The destination <#= item.XmlType #> instance to check the size for. /// The name of the input parameter being tested. /// Thrown if the size of is > the one of . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeLessThanOrEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, [CallerArgumentExpression("source")] string name = "") + public static void HasSizeLessThanOrEqualTo(<#= item.Type #> source, <#= item.DestinationType #> destination, [CallerArgumentExpression("source")] string name = "") { - if (source.<#=item.Size#> <= destination.<#=item.Size#>) + if (source.<#= item.Size #> <= destination.<#= item.Size #>) { return; } <# -if (item.HasCountProperty) -{ + if (item.HasCountProperty) + { #> - ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Cast#>source, destination.<#=item.Size#>, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#= item.Cast #>source, destination.<#= item.Size #>, name); <# -} -else -{ + } + else + { #> - ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, <#=item.Cast#>destination, name); + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, <#= item.Cast #>destination, name); <# -} + } #> } /// - /// Asserts that the input index is valid for a given <#=item.XmlType#> instance. + /// Asserts that the input index is valid for a given <#= item.XmlType #> instance. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input index to be used to access . - /// The input <#=item.XmlType#> instance to use to validate . + /// The item of items in the input <#= item.XmlType #> instance. + /// The input index to be used to access . + /// The input <#= item.XmlType #> instance to use to validate . /// The name of the input parameter being tested. - /// Thrown if is not valid to access . + /// Thrown if is not valid to access . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsInRangeFor(int index, <#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("index")] string name = "") + public static void IsInRangeFor(int index, <#= item.Type #> <#= item.Name #>, [CallerArgumentExpression("index")] string name = "") { <# -// Here we're leveraging the fact that signed integers are represented -// in 2-complement to perform the bounds check with a single compare operation. -// This is the same trick used throughout CoreCLR as well. -// For more info and code sample, see the original conversation here: -// https://github.com/CommunityToolkit/WindowsCommunityToolkit/pull/3131#discussion_r390682835 + // Here we're leveraging the fact that signed integers are represented + // in 2-complement to perform the bounds check with a single compare operation. + // This is the same trick used throughout CoreCLR as well. + // For more info and code sample, see the original conversation here: + // https://github.com/CommunityToolkit/WindowsCommunityToolkit/pull/3131#discussion_r390682835 #> - if ((uint)index < (uint)<#=item.Name#>.<#=item.Size#>) + if ((uint)index < (uint)<#= item.Name #>.<#= item.Size #>) { return; } - ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, <#=item.Cast#><#=item.Name#>, name); + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, <#= item.Cast #><#= item.Name #>, name); } /// - /// Asserts that the input index is not valid for a given <#=item.XmlType#> instance. + /// Asserts that the input index is not valid for a given <#= item.XmlType #> instance. /// - /// The item of items in the input <#=item.XmlType#> instance. - /// The input index to be used to access . - /// The input <#=item.XmlType#> instance to use to validate . + /// The item of items in the input <#= item.XmlType #> instance. + /// The input index to be used to access . + /// The input <#= item.XmlType #> instance to use to validate . /// The name of the input parameter being tested. - /// Thrown if is valid to access . + /// Thrown if is valid to access . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotInRangeFor(int index, <#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("index")] string name = "") + public static void IsNotInRangeFor(int index, <#= item.Type #> <#= item.Name #>, [CallerArgumentExpression("index")] string name = "") { - if ((uint)index >= (uint)<#=item.Name#>.<#=item.Size#>) + if ((uint)index >= (uint)<#= item.Name #>.<#= item.Size #>) { return; } - ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, <#=item.Cast#><#=item.Name#>, name); + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, <#= item.Cast #><#= item.Name #>, name); } <# -}); + }); #> } diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.tt b/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.tt index 23b4af2..2c0c417 100644 --- a/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.tt +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.tt @@ -10,19 +10,19 @@ namespace PerformanceFish.Utility.Diagnostics; partial class Guard { <# -GenerateTextForItems(NumericTypes, typeInfo => -{ -var (type, prefix) = typeInfo; + GenerateTextForItems(NumericTypes, typeInfo => + { + var (type, prefix) = typeInfo; #> /// /// Asserts that the input value must be equal to a specified value. /// - /// The input ="<#=type#>"/> value to test. - /// The target ="<#=type#>"/> value to test for. + /// The input ="<#= type #>"/> value to test. + /// The target ="<#= type #>"/> value to test for. /// The name of the input parameter being tested. /// Thrown if is != . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsEqualTo(<#=type#> value, <#=type#> target, [CallerArgumentExpression("value")] string name = "") + public static void IsEqualTo(<#= type #> value, <#= type #> target, [CallerArgumentExpression("value")] string name = "") { if (value == target) { @@ -35,13 +35,13 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be not equal to a specified value. /// - /// The input ="<#=type#>"/> value to test. - /// The target ="<#=type#>"/> value to test for. + /// The input ="<#= type #>"/> value to test. + /// The target ="<#= type #>"/> value to test for. /// The name of the input parameter being tested. /// Thrown if is == . /// The method is generic to avoid boxing the parameters, if they are value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotEqualTo(<#=type#> value, <#=type#> target, [CallerArgumentExpression("value")] string name = "") + public static void IsNotEqualTo(<#= type #> value, <#= type #> target, [CallerArgumentExpression("value")] string name = "") { if (value != target) { @@ -54,13 +54,13 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be less than a specified value. /// - /// The input ="<#=type#>"/> value to test. - /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The exclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is >= . /// The method is generic to avoid boxing the parameters, if they are value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsLessThan(<#=type#> value, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsLessThan(<#= type #> value, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value < maximum) { @@ -73,13 +73,13 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be less than or equal to a specified value. /// - /// The input ="<#=type#>"/> value to test. - /// The inclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The inclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is > . /// The method is generic to avoid boxing the parameters, if they are value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsLessThanOrEqualTo(<#=type#> value, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsLessThanOrEqualTo(<#= type #> value, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value <= maximum) { @@ -92,13 +92,13 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be greater than a specified value. /// - /// The input ="<#=type#>"/> value to test. - /// The exclusive minimum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The exclusive minimum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is <= . /// The method is generic to avoid boxing the parameters, if they are value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsGreaterThan(<#=type#> value, <#=type#> minimum, [CallerArgumentExpression("value")] string name = "") + public static void IsGreaterThan(<#= type #> value, <#= type #> minimum, [CallerArgumentExpression("value")] string name = "") { if (value > minimum) { @@ -111,13 +111,13 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be greater than or equal to a specified value. /// - /// The input ="<#=type#>"/> value to test. - /// The inclusive minimum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The inclusive minimum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is < . /// The method is generic to avoid boxing the parameters, if they are value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsGreaterThanOrEqualTo(<#=type#> value, <#=type#> minimum, [CallerArgumentExpression("value")] string name = "") + public static void IsGreaterThanOrEqualTo(<#= type #> value, <#= type #> minimum, [CallerArgumentExpression("value")] string name = "") { if (value >= minimum) { @@ -130,9 +130,9 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be in a given range. /// - /// The input ="<#=type#>"/> value to test. - /// The inclusive minimum ="<#=type#>"/> value that is accepted. - /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The inclusive minimum ="<#= type #>"/> value that is accepted. + /// The exclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is < or >= . /// @@ -140,7 +140,7 @@ var (type, prefix) = typeInfo; /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsInRange(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsInRange(<#= type #> value, <#= type #> minimum, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value >= minimum && value < maximum) { @@ -153,9 +153,9 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must not be in a given range. /// - /// The input ="<#=type#>"/> value to test. - /// The inclusive minimum ="<#=type#>"/> value that is accepted. - /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The inclusive minimum ="<#= type #>"/> value that is accepted. + /// The exclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is >= or < . /// @@ -163,7 +163,7 @@ var (type, prefix) = typeInfo; /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotInRange(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsNotInRange(<#= type #> value, <#= type #> minimum, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value < minimum || value >= maximum) { @@ -176,9 +176,9 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be in a given interval. /// - /// The input ="<#=type#>"/> value to test. - /// The exclusive minimum ="<#=type#>"/> value that is accepted. - /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The exclusive minimum ="<#= type #>"/> value that is accepted. + /// The exclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is <= or >= . /// @@ -186,7 +186,7 @@ var (type, prefix) = typeInfo; /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsBetween(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsBetween(<#= type #> value, <#= type #> minimum, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value > minimum && value < maximum) { @@ -199,9 +199,9 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must not be in a given interval. /// - /// The input ="<#=type#>"/> value to test. - /// The exclusive minimum ="<#=type#>"/> value that is accepted. - /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The exclusive minimum ="<#= type #>"/> value that is accepted. + /// The exclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is > or < . /// @@ -209,7 +209,7 @@ var (type, prefix) = typeInfo; /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotBetween(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsNotBetween(<#= type #> value, <#= type #> minimum, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value <= minimum || value >= maximum) { @@ -222,9 +222,9 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must be in a given interval. /// - /// The input ="<#=type#>"/> value to test. - /// The inclusive minimum ="<#=type#>"/> value that is accepted. - /// The inclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The inclusive minimum ="<#= type #>"/> value that is accepted. + /// The inclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is < or > . /// @@ -232,7 +232,7 @@ var (type, prefix) = typeInfo; /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsBetweenOrEqualTo(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsBetweenOrEqualTo(<#= type #> value, <#= type #> minimum, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value >= minimum && value <= maximum) { @@ -245,9 +245,9 @@ var (type, prefix) = typeInfo; /// /// Asserts that the input value must not be in a given interval. /// - /// The input ="<#=type#>"/> value to test. - /// The inclusive minimum ="<#=type#>"/> value that is accepted. - /// The inclusive maximum ="<#=type#>"/> value that is accepted. + /// The input ="<#= type #>"/> value to test. + /// The inclusive minimum ="<#= type #>"/> value that is accepted. + /// The inclusive maximum ="<#= type #>"/> value that is accepted. /// The name of the input parameter being tested. /// Thrown if is >= or <= . /// @@ -255,7 +255,7 @@ var (type, prefix) = typeInfo; /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotBetweenOrEqualTo(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsNotBetweenOrEqualTo(<#= type #> value, <#= type #> minimum, <#= type #> maximum, [CallerArgumentExpression("value")] string name = "") { if (value < minimum || value > maximum) { @@ -265,6 +265,6 @@ var (type, prefix) = typeInfo; ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); } <# -}); + }); #> } diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.md b/Source/FisheryLib/Diagnostics/Generated/Guard.md index b787eda..3af4878 100644 --- a/Source/FisheryLib/Diagnostics/Generated/Guard.md +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.md @@ -1,17 +1,29 @@ # T4 templates and generated APIs -This folder contains a number of template files (with the `.tt` or `.ttinclude` extensions) and the generated `.g.cs` files generated by those templates. The template files use the T4 format, which is natively supported by Visual Studio (more info is available [here](https://docs.microsoft.com/visualstudio/modeling/code-generation-and-t4-text-templates)). +This folder contains a number of template files (with the `.tt` or `.ttinclude` extensions) and the generated `.g.cs` +files generated by those templates. The template files use the T4 format, which is natively supported by Visual Studio ( +more info is available [here](https://docs.microsoft.com/visualstudio/modeling/code-generation-and-t4-text-templates)). ## Why is this needed? There are a few reasons why T4 templates are used for the `Guard` class: -- Especially when many overloads are available for an API, using templates makes it much easier to maintain code and spot mistakes, as the actual number of lines of code to review is much smaller: it's just the same code from each template! -- Using type-specific overloads instead of generic methods can result in faster code. For instance, T4 templates are used to generate overloads for comparison APIs (eg. `Guard.IsGreaterThan(int, int, string)`). This results in more compact and optimized code as opposed to a generic method using `where T : IComparable` as type constraint. -- In some cases, using generic methods just isn't possible. For instance, types like `Span` and `ReadOnlySpan` can't be used as generic type parameters, and even if that had been possible, they don't implement an interface we could use in the generic type constraint. Using T4 templates solves this issue, as we can just have specialized method for each supported type or collection type. +- Especially when many overloads are available for an API, using templates makes it much easier to maintain code and + spot mistakes, as the actual number of lines of code to review is much smaller: it's just the same code from each + template! +- Using type-specific overloads instead of generic methods can result in faster code. For instance, T4 templates are + used to generate overloads for comparison APIs (eg. `Guard.IsGreaterThan(int, int, string)`). This results in more + compact and optimized code as opposed to a generic method using `where T : IComparable` as type constraint. +- In some cases, using generic methods just isn't possible. For instance, types like `Span` and `ReadOnlySpan` + can't be used as generic type parameters, and even if that had been possible, they don't implement an interface we + could use in the generic type constraint. Using T4 templates solves this issue, as we can just have specialized method + for each supported type or collection type. ## How to make changes -If you need to change an API that is declared in a template, or to add a new one, just edit the right `.tt` file and save it: Visual Studio will take care of updating the generated `.g.cs` file automatically. Don't make changes to those generated `.g.cs` files directly, as those will be overwritten as soon as their source template is updated. +If you need to change an API that is declared in a template, or to add a new one, just edit the right `.tt` file and +save it: Visual Studio will take care of updating the generated `.g.cs` file automatically. Don't make changes to those +generated `.g.cs` files directly, as those will be overwritten as soon as their source template is updated. -Note that all the `.g.cs` files are checked in into the repository, so if you do make changes to a template file, make sure to also include the updated `.g.cs` file in your commits. +Note that all the `.g.cs` files are checked in into the repository, so if you do make changes to a template file, make +sure to also include the updated `.g.cs` file in your commits. diff --git a/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.tt b/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.tt index 86e7aa1..ed7d5bb 100644 --- a/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.tt +++ b/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.tt @@ -13,109 +13,109 @@ partial class Guard partial class ThrowHelper { <# -GenerateTextForItems(EnumerableTypes, item => -{ + GenerateTextForItems(EnumerableTypes, item => + { #> /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsEmpty(<#=item.Type#> <#=item.Name#>, string name) + public static void ThrowArgumentExceptionForIsEmpty(<#= item.Type #> <#= item.Name #>, string name) { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must be empty, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must be empty, had a size of {AssertString(<#= item.Name #>.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + public static void ThrowArgumentExceptionForHasSizeEqualTo(<#= item.Type #> <#= item.Name #>, int size, string name) { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(<#= item.Name #>.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeNotEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(<#= item.Type #> <#= item.Name #>, int size, string name) { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(<#= item.Name #>.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeGreaterThan(<#=item.Type#> <#=item.Name#>, int size, string name) + public static void ThrowArgumentExceptionForHasSizeGreaterThan(<#= item.Type #> <#= item.Name #>, int size, string name) { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(<#= item.Name #>.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(<#= item.Type #> <#= item.Name #>, int size, string name) { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(<#= item.Name #>.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeLessThan(<#=item.Type#> <#=item.Name#>, int size, string name) + public static void ThrowArgumentExceptionForHasSizeLessThan(<#= item.Type #> <#= item.Name #>, int size, string name) { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(<#= item.Name #>.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#= item.Type #> <#= item.Name #>, int size, string name) { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(<#= item.Name #>.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, string name) + public static void ThrowArgumentExceptionForHasSizeEqualTo(<#= item.Type #> source, <#= item.DestinationType #> destination, string name) { - throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size equal to {AssertString(destination.<#=item.Size#>)} (the destination), had a size of {AssertString(source.<#=item.Size#>)}.", name); + throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size equal to {AssertString(destination.<#= item.Size #>)} (the destination), had a size of {AssertString(source.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, string name) + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#= item.Type #> source, <#= item.DestinationType #> destination, string name) { - throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.<#=item.Size#>)} (the destination), had a size of {AssertString(source.<#=item.Size#>)}.", name); + throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#= item.Type #>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.<#= item.Size #>)} (the destination), had a size of {AssertString(source.<#= item.Size #>)}.", name); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, <#=item.Type#> <#=item.Name#>, string name) + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, <#= item.Type #> <#= item.Name #>, string name) { - throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(<#=item.Name#>.<#=item.Size#>)} to be a valid index for the target collection ({typeof(<#=item.Type#>).ToTypeString()}), was {AssertString(index)}."); + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(<#= item.Name #>.<#= item.Size #>)} to be a valid index for the target collection ({typeof(<#= item.Type #>).ToTypeString()}), was {AssertString(index)}."); } /// /// Throws an when (or an overload) fails. /// [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, <#=item.Type#> <#=item.Name#>, string name) + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, <#= item.Type #> <#= item.Name #>, string name) { - throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(<#=item.Name#>.<#=item.Size#>)} to be an invalid index for the target collection ({typeof(<#=item.Type#>).ToTypeString()}), was {AssertString(index)}."); + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(<#= item.Name #>.<#= item.Size #>)} to be an invalid index for the target collection ({typeof(<#= item.Type #>).ToTypeString()}), was {AssertString(index)}."); } <# -}); + }); #> } } diff --git a/Source/FisheryLib/Diagnostics/Generated/TypeInfo.ttinclude b/Source/FisheryLib/Diagnostics/Generated/TypeInfo.ttinclude index b2421dc..b320d9e 100644 --- a/Source/FisheryLib/Diagnostics/Generated/TypeInfo.ttinclude +++ b/Source/FisheryLib/Diagnostics/Generated/TypeInfo.ttinclude @@ -71,11 +71,14 @@ new EnumerableTypeInfo("Span", "", "span", "Length", "Span", ""), new EnumerableTypeInfo("ReadOnlySpan", "", "span", "Length", "Span", ""), new EnumerableTypeInfo("Memory", "", "memory", "Length", "Memory", ""), - new EnumerableTypeInfo("ReadOnlyMemory", "", "memory", "Length", "Memory", ""), + new EnumerableTypeInfo("ReadOnlyMemory", "", "memory", "Length", "Memory", + ""), new EnumerableTypeInfo("T[]", " array", "array", "Length", "T[]", ""), new EnumerableTypeInfo("List", "", "list", "Count", "List", "(ICollection)"), - new EnumerableTypeInfo("ICollection", "", "collection", "Count", "ICollection", ""), - new EnumerableTypeInfo("IReadOnlyCollection", "", "collection", "Count", "ICollection", ""), + new EnumerableTypeInfo("ICollection", "", "collection", "Count", + "ICollection", ""), + new EnumerableTypeInfo("IReadOnlyCollection", "", "collection", "Count", + "ICollection", "") }; /// @@ -107,10 +110,11 @@ for (int i = 0; i < items.Count; i++) { // Insert a blank line after the first item - if (i > 0) WriteLine(""); + if (i > 0) + WriteLine(""); // Invoke the factory with the current item - factory(items [i]); + factory(items[i]); } } #> \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.Boolean.cs b/Source/FisheryLib/Diagnostics/Guard.Boolean.cs index 7d38f1e..46327c4 100644 --- a/Source/FisheryLib/Diagnostics/Guard.Boolean.cs +++ b/Source/FisheryLib/Diagnostics/Guard.Boolean.cs @@ -20,9 +20,7 @@ public static partial class Guard public static void IsTrue([DoesNotReturnIf(false)] bool value, [CallerArgumentExpression("value")] string name = "") { if (value) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsTrue(name); } @@ -38,9 +36,7 @@ public static partial class Guard public static void IsTrue([DoesNotReturnIf(false)] bool value, string name, string message) { if (value) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsTrue(name, message); } @@ -55,9 +51,7 @@ public static partial class Guard public static void IsFalse([DoesNotReturnIf(true)] bool value, [CallerArgumentExpression("value")] string name = "") { if (!value) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsFalse(name); } @@ -73,9 +67,7 @@ public static partial class Guard public static void IsFalse([DoesNotReturnIf(true)] bool value, string name, string message) { if (!value) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsFalse(name, message); } @@ -155,7 +147,8 @@ public static partial class Guard { StringBuilder builder = new(); - this.handler = new StringBuilder.AppendInterpolatedStringHandler(literalLength, formattedCount, builder); + this.handler = + new StringBuilder.AppendInterpolatedStringHandler(literalLength, formattedCount, builder); this.builder = builder; shouldAppend = true; @@ -273,7 +266,8 @@ public static partial class Guard { StringBuilder builder = new(); - this.handler = new StringBuilder.AppendInterpolatedStringHandler(literalLength, formattedCount, builder); + this.handler = + new StringBuilder.AppendInterpolatedStringHandler(literalLength, formattedCount, builder); this.builder = builder; shouldAppend = true; @@ -353,4 +347,4 @@ public static partial class Guard } } #endif -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.Comparable.Generic.cs b/Source/FisheryLib/Diagnostics/Guard.Comparable.Generic.cs index 80c2ad3..2a34410 100644 --- a/Source/FisheryLib/Diagnostics/Guard.Comparable.Generic.cs +++ b/Source/FisheryLib/Diagnostics/Guard.Comparable.Generic.cs @@ -21,9 +21,7 @@ public partial class Guard where T : struct, IEquatable { if (value.Equals(default)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsDefault(value, name); } @@ -40,9 +38,7 @@ public partial class Guard where T : struct, IEquatable { if (!value.Equals(default)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotDefault(name); } @@ -61,9 +57,7 @@ public partial class Guard where T : notnull, IEquatable { if (value.Equals(target)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); } @@ -82,9 +76,7 @@ public partial class Guard where T : notnull, IEquatable { if (!value.Equals(target)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); } @@ -98,7 +90,8 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if is not a bitwise match for . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void IsBitwiseEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + public static unsafe void IsBitwiseEqualTo(T value, T target, + [CallerArgumentExpression("value")] string name = "") where T : unmanaged { // Include some fast paths if the input type is of size 1, 2, 4, 8, or 16. @@ -112,9 +105,7 @@ public partial class Guard var targetByte = Unsafe.As(ref target); if (valueByte == targetByte) - { return; - } ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); } @@ -124,9 +115,7 @@ public partial class Guard var targetUShort = Unsafe.As(ref target); if (valueUShort == targetUShort) - { return; - } ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); } @@ -136,9 +125,7 @@ public partial class Guard var targetUInt = Unsafe.As(ref target); if (valueUInt == targetUInt) - { return; - } ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); } @@ -148,9 +135,7 @@ public partial class Guard var targetULong = Unsafe.As(ref target); if (Bit64Compare(ref valueULong, ref targetULong)) - { return; - } ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); } @@ -165,9 +150,7 @@ public partial class Guard var targetULong1 = Unsafe.Add(ref Unsafe.As(ref target), 1); if (Bit64Compare(ref valueULong1, ref targetULong1)) - { return; - } } ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); @@ -178,9 +161,7 @@ public partial class Guard Span targetBytes = new(Unsafe.AsPointer(ref target), sizeof(T)); if (valueBytes.SequenceEqual(targetBytes)) - { return; - } ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); } @@ -196,8 +177,7 @@ public partial class Guard ref var r0 = ref Unsafe.As(ref left); ref var r1 = ref Unsafe.As(ref right); - return r0 == r1 && - Unsafe.Add(ref r0, 1) == Unsafe.Add(ref r1, 1); + return r0 == r1 && Unsafe.Add(ref r0, 1) == Unsafe.Add(ref r1, 1); } return left == right; @@ -217,9 +197,7 @@ public partial class Guard where T : notnull, IComparable { if (value.CompareTo(maximum) < 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); } @@ -238,9 +216,7 @@ public partial class Guard where T : notnull, IComparable { if (value.CompareTo(maximum) <= 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); } @@ -259,9 +235,7 @@ public partial class Guard where T : notnull, IComparable { if (value.CompareTo(minimum) > 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); } @@ -276,13 +250,12 @@ public partial class Guard /// Thrown if is < . /// The method is generic to avoid boxing the parameters, if they are value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsGreaterThanOrEqualTo(T value, T minimum, [CallerArgumentExpression("value")] string name = "") + public static void IsGreaterThanOrEqualTo(T value, T minimum, + [CallerArgumentExpression("value")] string name = "") where T : notnull, IComparable { if (value.CompareTo(minimum) >= 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); } @@ -305,9 +278,7 @@ public partial class Guard where T : notnull, IComparable { if (value.CompareTo(minimum) >= 0 && value.CompareTo(maximum) < 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); } @@ -326,13 +297,12 @@ public partial class Guard /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotInRange(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsNotInRange(T value, T minimum, T maximum, + [CallerArgumentExpression("value")] string name = "") where T : notnull, IComparable { if (value.CompareTo(minimum) < 0 || value.CompareTo(maximum) >= 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); } @@ -355,9 +325,7 @@ public partial class Guard where T : notnull, IComparable { if (value.CompareTo(minimum) > 0 && value.CompareTo(maximum) < 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); } @@ -376,13 +344,12 @@ public partial class Guard /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotBetween(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsNotBetween(T value, T minimum, T maximum, + [CallerArgumentExpression("value")] string name = "") where T : notnull, IComparable { if (value.CompareTo(minimum) <= 0 || value.CompareTo(maximum) >= 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); } @@ -401,13 +368,12 @@ public partial class Guard /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsBetweenOrEqualTo(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsBetweenOrEqualTo(T value, T minimum, T maximum, + [CallerArgumentExpression("value")] string name = "") where T : notnull, IComparable { if (value.CompareTo(minimum) >= 0 && value.CompareTo(maximum) <= 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); } @@ -426,14 +392,13 @@ public partial class Guard /// The method is generic to avoid boxing the parameters, if they are value types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotBetweenOrEqualTo(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + public static void IsNotBetweenOrEqualTo(T value, T minimum, T maximum, + [CallerArgumentExpression("value")] string name = "") where T : notnull, IComparable { if (value.CompareTo(minimum) < 0 || value.CompareTo(maximum) > 0) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.Comparable.Numeric.cs b/Source/FisheryLib/Diagnostics/Guard.Comparable.Numeric.cs index a208ad1..be408c6 100644 --- a/Source/FisheryLib/Diagnostics/Guard.Comparable.Numeric.cs +++ b/Source/FisheryLib/Diagnostics/Guard.Comparable.Numeric.cs @@ -18,14 +18,13 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) > . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsCloseTo(int value, int target, uint delta, [CallerArgumentExpression("value")] string name = "") + public static void IsCloseTo(int value, int target, uint delta, + [CallerArgumentExpression("value")] string name = "") { var difference = value >= target ? (uint)(value - target) : (uint)(target - value); if (difference <= delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); } @@ -39,14 +38,13 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) <= . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotCloseTo(int value, int target, uint delta, [CallerArgumentExpression("value")] string name = "") + public static void IsNotCloseTo(int value, int target, uint delta, + [CallerArgumentExpression("value")] string name = "") { var difference = value >= target ? (uint)(value - target) : (uint)(target - value); if (difference > delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); } @@ -60,14 +58,13 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) > . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsCloseTo(long value, long target, ulong delta, [CallerArgumentExpression("value")] string name = "") + public static void IsCloseTo(long value, long target, ulong delta, + [CallerArgumentExpression("value")] string name = "") { var difference = value >= target ? (ulong)(value - target) : (ulong)(target - value); if (difference <= delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); } @@ -81,14 +78,13 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) <= . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotCloseTo(long value, long target, ulong delta, [CallerArgumentExpression("value")] string name = "") + public static void IsNotCloseTo(long value, long target, ulong delta, + [CallerArgumentExpression("value")] string name = "") { var difference = value >= target ? (ulong)(value - target) : (ulong)(target - value); if (difference > delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); } @@ -102,12 +98,11 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) > . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsCloseTo(float value, float target, float delta, [CallerArgumentExpression("value")] string name = "") + public static void IsCloseTo(float value, float target, float delta, + [CallerArgumentExpression("value")] string name = "") { if (Math.Abs(value - target) <= delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); } @@ -121,12 +116,11 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) <= . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotCloseTo(float value, float target, float delta, [CallerArgumentExpression("value")] string name = "") + public static void IsNotCloseTo(float value, float target, float delta, + [CallerArgumentExpression("value")] string name = "") { if (Math.Abs(value - target) > delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); } @@ -140,12 +134,11 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) > . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsCloseTo(double value, double target, double delta, [CallerArgumentExpression("value")] string name = "") + public static void IsCloseTo(double value, double target, double delta, + [CallerArgumentExpression("value")] string name = "") { if (Math.Abs(value - target) <= delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); } @@ -159,12 +152,11 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) <= . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotCloseTo(double value, double target, double delta, [CallerArgumentExpression("value")] string name = "") + public static void IsNotCloseTo(double value, double target, double delta, + [CallerArgumentExpression("value")] string name = "") { if (Math.Abs(value - target) > delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); } @@ -178,14 +170,13 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) > . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsCloseTo(nint value, nint target, nuint delta, [CallerArgumentExpression("value")] string name = "") + public static void IsCloseTo(nint value, nint target, nuint delta, + [CallerArgumentExpression("value")] string name = "") { var difference = value >= target ? (nuint)(value - target) : (nuint)(target - value); if (difference <= delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); } @@ -199,15 +190,14 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if ( - ) <= . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotCloseTo(nint value, nint target, nuint delta, [CallerArgumentExpression("value")] string name = "") + public static void IsNotCloseTo(nint value, nint target, nuint delta, + [CallerArgumentExpression("value")] string name = "") { var difference = value >= target ? (nuint)(value - target) : (nuint)(target - value); if (difference > delta) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.IO.cs b/Source/FisheryLib/Diagnostics/Guard.IO.cs index e645849..af21ced 100644 --- a/Source/FisheryLib/Diagnostics/Guard.IO.cs +++ b/Source/FisheryLib/Diagnostics/Guard.IO.cs @@ -20,9 +20,7 @@ public partial class Guard public static void CanRead(Stream stream, [CallerArgumentExpression("stream")] string name = "") { if (stream.CanRead) - { return; - } ThrowHelper.ThrowArgumentExceptionForCanRead(stream, name); } @@ -37,9 +35,7 @@ public partial class Guard public static void CanWrite(Stream stream, [CallerArgumentExpression("stream")] string name = "") { if (stream.CanWrite) - { return; - } ThrowHelper.ThrowArgumentExceptionForCanWrite(stream, name); } @@ -54,9 +50,7 @@ public partial class Guard public static void CanSeek(Stream stream, [CallerArgumentExpression("stream")] string name = "") { if (stream.CanSeek) - { return; - } ThrowHelper.ThrowArgumentExceptionForCanSeek(stream, name); } @@ -71,10 +65,8 @@ public partial class Guard public static void IsAtStartPosition(Stream stream, [CallerArgumentExpression("stream")] string name = "") { if (stream.Position == 0) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsAtStartPosition(stream, name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.String.cs b/Source/FisheryLib/Diagnostics/Guard.String.cs index ebbab5f..b8b39d0 100644 --- a/Source/FisheryLib/Diagnostics/Guard.String.cs +++ b/Source/FisheryLib/Diagnostics/Guard.String.cs @@ -22,9 +22,7 @@ public partial class Guard public static void IsNullOrEmpty(string? text, [CallerArgumentExpression("text")] string name = "") { if (string.IsNullOrEmpty(text)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNullOrEmpty(text, name); } @@ -40,9 +38,7 @@ public partial class Guard public static void IsNotNullOrEmpty([NotNull] string? text, [CallerArgumentExpression("text")] string name = "") { if (!string.IsNullOrEmpty(text)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotNullOrEmpty(text, name); } @@ -57,9 +53,7 @@ public partial class Guard public static void IsNullOrWhiteSpace(string? text, [CallerArgumentExpression("text")] string name = "") { if (string.IsNullOrWhiteSpace(text)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNullOrWhiteSpace(text, name); } @@ -72,12 +66,11 @@ public partial class Guard /// Thrown if is . /// Thrown if is whitespace. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotNullOrWhiteSpace([NotNull] string? text, [CallerArgumentExpression("text")] string name = "") + public static void IsNotNullOrWhiteSpace([NotNull] string? text, + [CallerArgumentExpression("text")] string name = "") { if (!string.IsNullOrWhiteSpace(text)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotNullOrWhiteSpace(text, name); } @@ -92,9 +85,7 @@ public partial class Guard public static void IsEmpty(string text, [CallerArgumentExpression("text")] string name = "") { if (text.Length == 0) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsEmpty(text, name); } @@ -109,9 +100,7 @@ public partial class Guard public static void IsNotEmpty(string text, [CallerArgumentExpression("text")] string name = "") { if (text.Length != 0) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotEmpty(name); } @@ -126,9 +115,7 @@ public partial class Guard public static void IsWhiteSpace(string text, [CallerArgumentExpression("text")] string name = "") { if (string.IsNullOrWhiteSpace(text)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsWhiteSpace(text, name); } @@ -143,9 +130,7 @@ public partial class Guard public static void IsNotWhiteSpace(string text, [CallerArgumentExpression("text")] string name = "") { if (!string.IsNullOrWhiteSpace(text)) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotWhiteSpace(text, name); } @@ -161,9 +146,7 @@ public partial class Guard public static void HasSizeEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") { if (text.Length == size) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(text, size, name); } @@ -179,9 +162,7 @@ public partial class Guard public static void HasSizeNotEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") { if (text.Length != size) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(text, size, name); } @@ -197,9 +178,7 @@ public partial class Guard public static void HasSizeGreaterThan(string text, int size, [CallerArgumentExpression("text")] string name = "") { if (text.Length > size) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(text, size, name); } @@ -212,12 +191,11 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if the size of is < . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeGreaterThanOrEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") + public static void HasSizeGreaterThanOrEqualTo(string text, int size, + [CallerArgumentExpression("text")] string name = "") { if (text.Length >= size) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(text, size, name); } @@ -233,9 +211,7 @@ public partial class Guard public static void HasSizeLessThan(string text, int size, [CallerArgumentExpression("text")] string name = "") { if (text.Length < size) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(text, size, name); } @@ -248,12 +224,11 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if the size of is > . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeLessThanOrEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") + public static void HasSizeLessThanOrEqualTo(string text, int size, + [CallerArgumentExpression("text")] string name = "") { if (text.Length <= size) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(text, size, name); } @@ -267,12 +242,11 @@ public partial class Guard /// Thrown if the size of is != the one of . /// The type is immutable, but the name of this API is kept for consistency with the other overloads. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeEqualTo(string text, string destination, [CallerArgumentExpression("text")] string name = "") + public static void HasSizeEqualTo(string text, string destination, + [CallerArgumentExpression("text")] string name = "") { if (text.Length == destination.Length) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(text, destination, name); } @@ -286,12 +260,11 @@ public partial class Guard /// Thrown if the size of is > the one of . /// The type is immutable, but the name of this API is kept for consistency with the other overloads. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasSizeLessThanOrEqualTo(string text, string destination, [CallerArgumentExpression("text")] string name = "") + public static void HasSizeLessThanOrEqualTo(string text, string destination, + [CallerArgumentExpression("text")] string name = "") { if (text.Length <= destination.Length) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(text, destination, name); } @@ -307,9 +280,7 @@ public partial class Guard public static void IsInRangeFor(int index, string text, [CallerArgumentExpression("index")] string name = "") { if ((uint)index < (uint)text.Length) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, text, name); } @@ -325,10 +296,8 @@ public partial class Guard public static void IsNotInRangeFor(int index, string text, [CallerArgumentExpression("index")] string name = "") { if ((uint)index >= (uint)text.Length) - { return; - } ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, text, name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.Tasks.cs b/Source/FisheryLib/Diagnostics/Guard.Tasks.cs index ee38611..b3d611c 100644 --- a/Source/FisheryLib/Diagnostics/Guard.Tasks.cs +++ b/Source/FisheryLib/Diagnostics/Guard.Tasks.cs @@ -20,9 +20,7 @@ public partial class Guard public static void IsCompleted(Task task, [CallerArgumentExpression("task")] string name = "") { if (task.IsCompleted) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCompleted(task, name); } @@ -37,9 +35,7 @@ public partial class Guard public static void IsNotCompleted(Task task, [CallerArgumentExpression("task")] string name = "") { if (!task.IsCompleted) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCompleted(task, name); } @@ -54,9 +50,7 @@ public partial class Guard public static void IsCompletedSuccessfully(Task task, [CallerArgumentExpression("task")] string name = "") { if (task.Status == TaskStatus.RanToCompletion) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCompletedSuccessfully(task, name); } @@ -71,9 +65,7 @@ public partial class Guard public static void IsNotCompletedSuccessfully(Task task, [CallerArgumentExpression("task")] string name = "") { if (task.Status != TaskStatus.RanToCompletion) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCompletedSuccessfully(task, name); } @@ -88,9 +80,7 @@ public partial class Guard public static void IsFaulted(Task task, [CallerArgumentExpression("task")] string name = "") { if (task.IsFaulted) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsFaulted(task, name); } @@ -105,9 +95,7 @@ public partial class Guard public static void IsNotFaulted(Task task, [CallerArgumentExpression("task")] string name = "") { if (!task.IsFaulted) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotFaulted(task, name); } @@ -122,9 +110,7 @@ public partial class Guard public static void IsCanceled(Task task, [CallerArgumentExpression("task")] string name = "") { if (task.IsCanceled) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsCanceled(task, name); } @@ -139,9 +125,7 @@ public partial class Guard public static void IsNotCanceled(Task task, [CallerArgumentExpression("task")] string name = "") { if (!task.IsCanceled) - { return; - } ThrowHelper.ThrowArgumentExceptionForIsNotCanceled(task, name); } @@ -154,12 +138,11 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if doesn't match . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasStatusEqualTo(Task task, TaskStatus status, [CallerArgumentExpression("task")] string name = "") + public static void HasStatusEqualTo(Task task, TaskStatus status, + [CallerArgumentExpression("task")] string name = "") { if (task.Status == status) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasStatusEqualTo(task, status, name); } @@ -172,13 +155,12 @@ public partial class Guard /// The name of the input parameter being tested. /// Thrown if matches . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void HasStatusNotEqualTo(Task task, TaskStatus status, [CallerArgumentExpression("task")] string name = "") + public static void HasStatusNotEqualTo(Task task, TaskStatus status, + [CallerArgumentExpression("task")] string name = "") { if (task.Status != status) - { return; - } ThrowHelper.ThrowArgumentExceptionForHasStatusNotEqualTo(task, status, name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.cs b/Source/FisheryLib/Diagnostics/Guard.cs index a3aeff4..b370723 100644 --- a/Source/FisheryLib/Diagnostics/Guard.cs +++ b/Source/FisheryLib/Diagnostics/Guard.cs @@ -3,8 +3,9 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using JetBrains.Annotations; +using NotNullAttribute = System.Diagnostics.CodeAnalysis.NotNullAttribute; namespace FisheryLib.Utility.Diagnostics; @@ -12,6 +13,7 @@ namespace FisheryLib.Utility.Diagnostics; /// Helper methods to verify conditions when running code. /// [DebuggerStepThrough] +[PublicAPI] public static partial class Guard { /// @@ -22,7 +24,7 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if is not . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNull(T? value, [CallerArgumentExpression("value")] string name = "") + public static void IsNull([NoEnumeration] T? value, [CallerArgumentExpression("value")] string name = "") { if (value is null) return; @@ -38,7 +40,7 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if is not . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNull(T? value, [CallerArgumentExpression("value")] string name = "") + public static void IsNull([NoEnumeration] T? value, [CallerArgumentExpression("value")] string name = "") where T : struct { if (value is null) @@ -55,7 +57,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if is . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotNull([NotNull] T? value, [CallerArgumentExpression("value")] string name = "") + public static void IsNotNull([NoEnumeration] [NotNull] T? value, + [CallerArgumentExpression("value")] string name = "") { if (value is not null) return; @@ -71,7 +74,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if is . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotNull([NotNull] T? value, [CallerArgumentExpression("value")] string name = "") + public static void IsNotNull([NoEnumeration] [NotNull] T? value, + [CallerArgumentExpression("value")] string name = "") where T : struct { if (value is not null) @@ -88,7 +92,7 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if is not of type . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsOfType(object value, [CallerArgumentExpression("value")] string name = "") + public static void IsOfType([NoEnumeration] object value, [CallerArgumentExpression("value")] string name = "") { if (value.GetType() == typeof(T)) return; @@ -104,7 +108,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if is of type . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotOfType(object value, [CallerArgumentExpression("value")] string name = "") + public static void IsNotOfType([NoEnumeration] object value, + [CallerArgumentExpression("value")] string name = "") { if (value.GetType() != typeof(T)) return; @@ -120,7 +125,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if the type of is not the same as . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsOfType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + public static void IsOfType([NoEnumeration] object value, Type type, + [CallerArgumentExpression("value")] string name = "") { if (value.GetType() == type) return; @@ -136,7 +142,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if the type of is the same as . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotOfType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + public static void IsNotOfType([NoEnumeration] object value, Type type, + [CallerArgumentExpression("value")] string name = "") { if (value.GetType() != type) return; @@ -152,7 +159,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if can't be assigned to type . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsAssignableToType(object value, [CallerArgumentExpression("value")] string name = "") + public static void IsAssignableToType([NoEnumeration] object value, + [CallerArgumentExpression("value")] string name = "") { if (value is T) return; @@ -168,7 +176,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if can be assigned to type . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotAssignableToType(object value, [CallerArgumentExpression("value")] string name = "") + public static void IsNotAssignableToType([NoEnumeration] object value, + [CallerArgumentExpression("value")] string name = "") { if (value is not T) return; @@ -184,7 +193,8 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if can't be assigned to . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsAssignableToType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + public static void IsAssignableToType([NoEnumeration] object value, Type type, + [CallerArgumentExpression("value")] string name = "") { if (type.IsInstanceOfType(value)) return; @@ -200,13 +210,48 @@ public static partial class Guard /// The name of the input parameter being tested. /// Thrown if can be assigned to . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsNotAssignableToType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + public static void IsNotAssignableToType([NoEnumeration] object value, Type type, + [CallerArgumentExpression("value")] string name = "") { if (!type.IsInstanceOfType(value)) return; ThrowHelper.ThrowArgumentExceptionForIsNotAssignableToType(value, type, name); } + + /// + /// Asserts that the input type can be assigned to a specified type. + /// + /// The input to test. + /// The type to look for. + /// The name of the input parameter being tested. + /// Thrown if can't be assigned to . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsTypeAssignableToType([NoEnumeration] Type value, Type type, + [CallerArgumentExpression("value")] string name = "") + { + if (type.IsAssignableFrom(value)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsAssignableToType(value, type, name); + } + + /// + /// Asserts that the input type can't be assigned to a specified type. + /// + /// The input to test. + /// The type to look for. + /// The name of the input parameter being tested. + /// Thrown if can be assigned to . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsTypeNotAssignableToType([NoEnumeration] Type value, Type type, + [CallerArgumentExpression("value")] string name = "") + { + if (!type.IsAssignableFrom(value)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsNotAssignableToType(value, type, name); + } /// /// Asserts that the input value must be the same instance as the target value. @@ -218,7 +263,8 @@ public static partial class Guard /// Thrown if is not the same instance as . /// The method is generic to prevent using it with value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsReferenceEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + public static void IsReferenceEqualTo([NoEnumeration] T value, T target, + [CallerArgumentExpression("value")] string name = "") where T : class { if (ReferenceEquals(value, target)) @@ -237,7 +283,8 @@ public static partial class Guard /// Thrown if is the same instance as . /// The method is generic to prevent using it with value types. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IsReferenceNotEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + public static void IsReferenceNotEqualTo([NoEnumeration] T value, T target, + [CallerArgumentExpression("value")] string name = "") where T : class { if (!ReferenceEquals(value, target)) @@ -245,4 +292,4 @@ public static partial class Guard ThrowHelper.ThrowArgumentExceptionForIsReferenceNotEqualTo(name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Collection.Generic.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Collection.Generic.ThrowHelper.cs index 4d13d6d..df280e7 100644 --- a/Source/FisheryLib/Diagnostics/Internals/Guard.Collection.Generic.ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Collection.Generic.ThrowHelper.cs @@ -19,9 +19,8 @@ public partial class Guard /// This method is needed because can't be used as a generic type parameter. [DoesNotReturn] public static void ThrowArgumentExceptionForIsNotEmptyWithSpan(string name) - { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must not be empty.", name); - } + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must not be empty.", name); /// /// Throws an when fails. @@ -30,9 +29,8 @@ public partial class Guard /// This method is needed because can't be used as a generic type parameter. [DoesNotReturn] public static void ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan(string name) - { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must not be empty.", name); - } + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must not be empty.", name); /// /// Throws an when (or an overload) fails. @@ -40,8 +38,7 @@ public partial class Guard /// The item of items in the input collection. [DoesNotReturn] public static void ThrowArgumentExceptionForIsNotEmpty(string name) - { - throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be empty.", name); - } + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be empty.", name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Generic.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Generic.ThrowHelper.cs index 2264eba..179613b 100644 --- a/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Generic.ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Generic.ThrowHelper.cs @@ -18,7 +18,10 @@ public partial class Guard /// The type of value type being tested. [DoesNotReturn] public static void ThrowArgumentExceptionForIsDefault(T value, string name) - where T : struct => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the default value {AssertString(default(T))}, was {AssertString(value)}.", name); + where T : struct + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the default value {AssertString(default(T))}, was {AssertString(value)}.", + name); /// /// Throws an when fails. @@ -26,21 +29,30 @@ public partial class Guard /// The type of value type being tested. [DoesNotReturn] public static void ThrowArgumentExceptionForIsNotDefault(string name) - where T : struct => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the default value {AssertString(default(T))}.", name); + where T : struct + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the default value {AssertString(default(T))}.", + name); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentExceptionForIsEqualTo(T value, T target, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be equal to {AssertString(target)}, was {AssertString(value)}.", name); + public static void ThrowArgumentExceptionForIsEqualTo(T value, T target, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be equal to {AssertString(target)}, was {AssertString(value)}.", + name); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotEqualTo(T value, T target, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be equal to {AssertString(target)}, was {AssertString(value)}.", name); + public static void ThrowArgumentExceptionForIsNotEqualTo(T value, T target, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be equal to {AssertString(target)}, was {AssertString(value)}.", + name); /// /// Throws an when fails. @@ -48,76 +60,103 @@ public partial class Guard /// The type of input values being compared. [DoesNotReturn] public static void ThrowArgumentExceptionForBitwiseEqualTo(T value, T target, string name) - where T : unmanaged => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) is not a bitwise match, was <{value.ToHexString()}> instead of <{target.ToHexString()}>.", name); + where T : unmanaged + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) is not a bitwise match, was <{value.ToHexString()}> instead of <{target.ToHexString()}>.", + name); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsLessThan(T value, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than {AssertString(maximum)}, was {AssertString(value)}."); + public static void ThrowArgumentOutOfRangeExceptionForIsLessThan(T value, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than {AssertString(maximum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(T value, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than or equal to {AssertString(maximum)}, was {AssertString(value)}."); + public static void ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(T value, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than or equal to {AssertString(maximum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThan(T value, T minimum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than {AssertString(minimum)}, was {AssertString(value)}."); + public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThan(T value, T minimum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than {AssertString(minimum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(T value, T minimum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than or equal to {AssertString(minimum)}, was {AssertString(value)}."); + public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(T value, T minimum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than or equal to {AssertString(minimum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsInRange(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + public static void ThrowArgumentOutOfRangeExceptionForIsInRange(T value, T minimum, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsNotInRange(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + public static void + ThrowArgumentOutOfRangeExceptionForIsNotInRange(T value, T minimum, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsBetween(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + public static void ThrowArgumentOutOfRangeExceptionForIsBetween(T value, T minimum, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsNotBetween(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + public static void + ThrowArgumentOutOfRangeExceptionForIsNotBetween(T value, T minimum, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + public static void + ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(T value, T minimum, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); /// /// Throws an when fails. /// /// The type of values being tested. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + public static void + ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(T value, T minimum, T maximum, string name) + => throw new ArgumentOutOfRangeException(name, value!, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Numeric.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Numeric.ThrowHelper.cs index 4810078..b37fd62 100644 --- a/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Numeric.ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Numeric.ThrowHelper.cs @@ -16,60 +16,90 @@ public partial class Guard /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCloseTo(int value, int target, uint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}.", name); + public static void ThrowArgumentExceptionForIsCloseTo(int value, int target, uint delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCloseTo(int value, int target, uint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}.", name); + public static void ThrowArgumentExceptionForIsNotCloseTo(int value, int target, uint delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCloseTo(long value, long target, ulong delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}.", name); + public static void ThrowArgumentExceptionForIsCloseTo(long value, long target, ulong delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCloseTo(long value, long target, ulong delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}.", name); + public static void ThrowArgumentExceptionForIsNotCloseTo(long value, long target, ulong delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCloseTo(float value, float target, float delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + public static void ThrowArgumentExceptionForIsCloseTo(float value, float target, float delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCloseTo(float value, float target, float delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + public static void ThrowArgumentExceptionForIsNotCloseTo(float value, float target, float delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCloseTo(double value, double target, double delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + public static void ThrowArgumentExceptionForIsCloseTo(double value, double target, double delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCloseTo(double value, double target, double delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + public static void ThrowArgumentExceptionForIsNotCloseTo(double value, double target, double delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCloseTo(nint value, nint target, nuint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + public static void ThrowArgumentExceptionForIsCloseTo(nint value, nint target, nuint delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCloseTo(nint value, nint target, nuint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + public static void ThrowArgumentExceptionForIsNotCloseTo(nint value, nint target, nuint delta, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", + name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.IO.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.IO.ThrowHelper.cs index 9053433..165861b 100644 --- a/Source/FisheryLib/Diagnostics/Internals/Guard.IO.ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.IO.ThrowHelper.cs @@ -17,24 +17,33 @@ public partial class Guard /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForCanRead(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support reading.", name); + public static void ThrowArgumentExceptionForCanRead(Stream stream, string name) + => throw new ArgumentException( + $"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support reading.", name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForCanWrite(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support writing.", name); + public static void ThrowArgumentExceptionForCanWrite(Stream stream, string name) + => throw new ArgumentException( + $"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support writing.", name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForCanSeek(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support seeking.", name); + public static void ThrowArgumentExceptionForCanSeek(Stream stream, string name) + => throw new ArgumentException( + $"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support seeking.", name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsAtStartPosition(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) must be at position {AssertString(0)}, was at {AssertString(stream.Position)}.", name); + public static void ThrowArgumentExceptionForIsAtStartPosition(Stream stream, string name) + => throw new ArgumentException( + $"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) must be at position {AssertString(0)}, was at {AssertString(stream.Position)}.", + name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.String.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.String.ThrowHelper.cs index 0ff9c6e..0ec8b94 100644 --- a/Source/FisheryLib/Diagnostics/Internals/Guard.String.ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.String.ThrowHelper.cs @@ -18,7 +18,8 @@ public partial class Guard /// [DoesNotReturn] public static void ThrowArgumentExceptionForIsNullOrEmpty(string? text, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be null or empty, was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must be null or empty, was {AssertString(text)}.", name); /// /// Throws an or when fails. @@ -29,8 +30,10 @@ public partial class Guard [MethodImpl(MethodImplOptions.NoInlining)] static Exception GetException(string? text, string name) => text is null - ? new ArgumentNullException(name, $"Parameter {AssertString(name)} (string) must not be null or empty, was null.") - : new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or empty, was empty.", name); + ? new ArgumentNullException(name, + $"Parameter {AssertString(name)} (string) must not be null or empty, was null.") + : new ArgumentException( + $"Parameter {AssertString(name)} (string) must not be null or empty, was empty.", name); throw GetException(text, name); } @@ -40,7 +43,8 @@ public partial class Guard /// [DoesNotReturn] public static void ThrowArgumentExceptionForIsNullOrWhiteSpace(string? text, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be null or whitespace, was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must be null or whitespace, was {AssertString(text)}.", name); /// /// Throws an when fails. @@ -51,8 +55,11 @@ public partial class Guard [MethodImpl(MethodImplOptions.NoInlining)] static Exception GetException(string? text, string name) => text is null - ? new ArgumentNullException(name, $"Parameter {AssertString(name)} (string) must not be null or whitespace, was null.") - : new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or whitespace, was whitespace.", name); + ? new ArgumentNullException(name, + $"Parameter {AssertString(name)} (string) must not be null or whitespace, was null.") + : new ArgumentException( + $"Parameter {AssertString(name)} (string) must not be null or whitespace, was whitespace.", + name); throw GetException(text, name); } @@ -62,7 +69,8 @@ public partial class Guard /// [DoesNotReturn] public static void ThrowArgumentExceptionForIsEmpty(string text, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be empty, was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must be empty, was {AssertString(text)}.", name); /// /// Throws an when fails. @@ -76,83 +84,104 @@ public partial class Guard /// [DoesNotReturn] public static void ThrowArgumentExceptionForIsWhiteSpace(string text, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be whitespace, was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must be whitespace, was {AssertString(text)}.", name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForIsNotWhiteSpace(string text, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be whitespace, was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must not be whitespace, was {AssertString(text)}.", name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForHasSizeEqualTo(string text, int size, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size equal to {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must have a size equal to {size}, had a size of {text.Length} and was {AssertString(text)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForHasSizeNotEqualTo(string text, int size, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must not have a size equal to {size}, was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must not have a size equal to {size}, was {AssertString(text)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForHasSizeGreaterThan(string text, int size, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size over {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must have a size over {size}, had a size of {text.Length} and was {AssertString(text)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(string text, int size, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size of at least {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must have a size of at least {size}, had a size of {text.Length} and was {AssertString(text)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForHasSizeLessThan(string text, int size, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size less than {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must have a size less than {size}, had a size of {text.Length} and was {AssertString(text)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(string text, int size, string name) - => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size less than or equal to {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + => throw new ArgumentException( + $"Parameter {AssertString(name)} (string) must have a size less than or equal to {size}, had a size of {text.Length} and was {AssertString(text)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentExceptionForHasSizeEqualTo(string source, string destination, string name) - => throw new ArgumentException($"The source {AssertString(name)} (string) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + => throw new ArgumentException( + $"The source {AssertString(name)} (string) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(string source, string destination, string name) - => throw new ArgumentException($"The source {AssertString(name)} (string) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + public static void + ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(string source, string destination, string name) + => throw new ArgumentException( + $"The source {AssertString(name)} (string) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, string text, string name) - => throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(text.Length)} to be a valid index for the target string, was {AssertString(index)}."); + => throw new ArgumentOutOfRangeException(name, index, + $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(text.Length)} to be a valid index for the target string, was {AssertString(index)}."); /// /// Throws an when fails. /// [DoesNotReturn] public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, string text, string name) - => throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(text.Length)} to be an invalid index for the target string, was {AssertString(index)}."); + => throw new ArgumentOutOfRangeException(name, index, + $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(text.Length)} to be an invalid index for the target string, was {AssertString(index)}."); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Tasks.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Tasks.ThrowHelper.cs index 4f46fab..f0a7469 100644 --- a/Source/FisheryLib/Diagnostics/Internals/Guard.Tasks.ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Tasks.ThrowHelper.cs @@ -17,60 +17,90 @@ public partial class Guard /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCompleted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsCompleted(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCompleted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsNotCompleted(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCompletedSuccessfully(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed successfully, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsCompletedSuccessfully(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed successfully, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCompletedSuccessfully(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed successfully, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsNotCompletedSuccessfully(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed successfully, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsFaulted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be faulted, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsFaulted(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be faulted, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotFaulted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be faulted, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsNotFaulted(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be faulted, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsCanceled(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be canceled, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsCanceled(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be canceled, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotCanceled(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be canceled, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForIsNotCanceled(Task task, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be canceled, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasStatusEqualTo(Task task, TaskStatus status, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must have status {status}, had status {AssertString(task.Status)}.", name); + public static void ThrowArgumentExceptionForHasStatusEqualTo(Task task, TaskStatus status, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must have status {status}, had status {AssertString(task.Status)}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForHasStatusNotEqualTo(Task task, TaskStatus status, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not have status {AssertString(status)}.", name); + public static void ThrowArgumentExceptionForHasStatusNotEqualTo(Task task, TaskStatus status, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not have status {AssertString(status)}.", + name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.ThrowHelper.cs index df45c9b..4bc296d 100644 --- a/Source/FisheryLib/Diagnostics/Internals/Guard.ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.ThrowHelper.cs @@ -32,7 +32,10 @@ public partial class Guard /// /// The type of the input value. [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNull(T value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be null, was {AssertString(value)} ({value!.GetType().ToTypeString()}).", name); + public static void ThrowArgumentExceptionForIsNull(T value, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be null, was {AssertString(value)} ({value!.GetType().ToTypeString()}).", + name); /// /// Throws an when (where is ) fails. @@ -40,66 +43,95 @@ public partial class Guard /// The type of the input value. [DoesNotReturn] public static void ThrowArgumentExceptionForIsNull(T? value, string name) - where T : struct => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T?).ToTypeString()}) must be null, was {AssertString(value)} ({typeof(T).ToTypeString()}).", name); + where T : struct + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T?).ToTypeString()}) must be null, was {AssertString(value)} ({typeof(T).ToTypeString()}).", + name); /// /// Throws an when fails. /// /// The type of the input value. [DoesNotReturn] - public static void ThrowArgumentNullExceptionForIsNotNull(string name) => throw new ArgumentNullException(name, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be not null)."); + public static void ThrowArgumentNullExceptionForIsNotNull(string name) + => throw new ArgumentNullException(name, + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be not null)."); /// /// Throws an when fails. /// /// The type of the input value. [DoesNotReturn] - public static void ThrowArgumentExceptionForIsOfType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsOfType(object value, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. /// /// The type of the input value. [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotOfType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsNotOfType(object value, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must not be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsOfType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsOfType(object value, Type type, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotOfType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsNotOfType(object value, Type type, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must not be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. /// /// The type being checked against. [DoesNotReturn] - public static void ThrowArgumentExceptionForIsAssignableToType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsAssignableToType(object value, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. /// /// The type being checked against. [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotAssignableToType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsNotAssignableToType(object value, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must not be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsAssignableToType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsAssignableToType(object value, Type type, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsNotAssignableToType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + public static void ThrowArgumentExceptionForIsNotAssignableToType(object value, Type type, string name) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must not be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", + name); /// /// Throws an when fails. @@ -107,7 +139,10 @@ public partial class Guard /// The type of input value being compared. [DoesNotReturn] public static void ThrowArgumentExceptionForIsReferenceEqualTo(string name) - where T : class => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the same instance as the target object.", name); + where T : class + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the same instance as the target object.", + name); /// /// Throws an when fails. @@ -115,30 +150,39 @@ public partial class Guard /// The type of input value being compared. [DoesNotReturn] public static void ThrowArgumentExceptionForIsReferenceNotEqualTo(string name) - where T : class => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the same instance as the target object.", name); + where T : class + => throw new ArgumentException( + $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the same instance as the target object.", + name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsTrue(string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false.", name); + public static void ThrowArgumentExceptionForIsTrue(string name) + => throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false.", name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsTrue(string name, string message) => throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false: {AssertString(message)}.", name); + public static void ThrowArgumentExceptionForIsTrue(string name, string message) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must be true, was false: {AssertString(message)}.", name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsFalse(string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true.", name); + public static void ThrowArgumentExceptionForIsFalse(string name) + => throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true.", name); /// /// Throws an when fails. /// [DoesNotReturn] - public static void ThrowArgumentExceptionForIsFalse(string name, string message) => throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true: {AssertString(message)}.", name); + public static void ThrowArgumentExceptionForIsFalse(string name, string message) + => throw new ArgumentException( + $"Parameter {AssertString(name)} must be false, was true: {AssertString(message)}.", name); } -} +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/ThrowHelper.Generic.cs b/Source/FisheryLib/Diagnostics/ThrowHelper.Generic.cs index e04a2b7..202eace 100644 --- a/Source/FisheryLib/Diagnostics/ThrowHelper.Generic.cs +++ b/Source/FisheryLib/Diagnostics/ThrowHelper.Generic.cs @@ -30,7 +30,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArrayTypeMismatchException(string? message) => throw new ArrayTypeMismatchException(message); + public static T ThrowArrayTypeMismatchException(string? message) + => throw new ArrayTypeMismatchException(message); /// /// Throws a new . @@ -41,7 +42,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArrayTypeMismatchException(string? message, Exception? innerException) => throw new ArrayTypeMismatchException(message, innerException); + public static T ThrowArrayTypeMismatchException(string? message, Exception? innerException) + => throw new ArrayTypeMismatchException(message, innerException); /// /// Throws a new . @@ -71,7 +73,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentException(string? message, Exception? innerException) => throw new ArgumentException(message, innerException); + public static T ThrowArgumentException(string? message, Exception? innerException) + => throw new ArgumentException(message, innerException); /// /// Throws a new . @@ -82,7 +85,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentException(string? name, string? message) => throw new ArgumentException(message, name); + public static T ThrowArgumentException(string? name, string? message) + => throw new ArgumentException(message, name); /// /// Throws a new . @@ -94,7 +98,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentException(string? name, string? message, Exception? innerException) => throw new ArgumentException(message, name, innerException); + public static T ThrowArgumentException(string? name, string? message, Exception? innerException) + => throw new ArgumentException(message, name, innerException); /// /// Throws a new . @@ -124,7 +129,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentNullException(string? name, Exception? innerException) => throw new ArgumentNullException(name, innerException); + public static T ThrowArgumentNullException(string? name, Exception? innerException) + => throw new ArgumentNullException(name, innerException); /// /// Throws a new . @@ -135,7 +141,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentNullException(string? name, string? message) => throw new ArgumentNullException(name, message); + public static T ThrowArgumentNullException(string? name, string? message) + => throw new ArgumentNullException(name, message); /// /// Throws a new . @@ -165,7 +172,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentOutOfRangeException(string? name, Exception? innerException) => throw new ArgumentOutOfRangeException(name, innerException); + public static T ThrowArgumentOutOfRangeException(string? name, Exception? innerException) + => throw new ArgumentOutOfRangeException(name, innerException); /// /// Throws a new . @@ -176,7 +184,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentOutOfRangeException(string? name, string? message) => throw new ArgumentOutOfRangeException(name, message); + public static T ThrowArgumentOutOfRangeException(string? name, string? message) + => throw new ArgumentOutOfRangeException(name, message); /// /// Throws a new . @@ -188,7 +197,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowArgumentOutOfRangeException(string? name, object? value, string? message) => throw new ArgumentOutOfRangeException(name, value, message); + public static T ThrowArgumentOutOfRangeException(string? name, object? value, string? message) + => throw new ArgumentOutOfRangeException(name, value, message); /// /// Throws a new . @@ -218,7 +228,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowCOMException(string? message, Exception? innerException) => throw new COMException(message, innerException); + public static T ThrowCOMException(string? message, Exception? innerException) + => throw new COMException(message, innerException); /// /// Throws a new . @@ -259,7 +270,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowExternalException(string? message, Exception? innerException) => throw new ExternalException(message, innerException); + public static T ThrowExternalException(string? message, Exception? innerException) + => throw new ExternalException(message, innerException); /// /// Throws a new . @@ -270,7 +282,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowExternalException(string? message, int error) => throw new ExternalException(message, error); + public static T ThrowExternalException(string? message, int error) + => throw new ExternalException(message, error); /// /// Throws a new . @@ -300,7 +313,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowFormatException(string? message, Exception? innerException) => throw new FormatException(message, innerException); + public static T ThrowFormatException(string? message, Exception? innerException) + => throw new FormatException(message, innerException); /// /// Throws a new . @@ -319,7 +333,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowInsufficientMemoryException(string? message) => throw new InsufficientMemoryException(message); + public static T ThrowInsufficientMemoryException(string? message) + => throw new InsufficientMemoryException(message); /// /// Throws a new . @@ -330,7 +345,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowInsufficientMemoryException(string? message, Exception? innerException) => throw new InsufficientMemoryException(message, innerException); + public static T ThrowInsufficientMemoryException(string? message, Exception? innerException) + => throw new InsufficientMemoryException(message, innerException); /// /// Throws a new . @@ -360,7 +376,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowInvalidDataException(string? message, Exception? innerException) => throw new InvalidDataException(message, innerException); + public static T ThrowInvalidDataException(string? message, Exception? innerException) + => throw new InvalidDataException(message, innerException); /// /// Throws a new . @@ -390,7 +407,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowInvalidOperationException(string? message, Exception? innerException) => throw new InvalidOperationException(message, innerException); + public static T ThrowInvalidOperationException(string? message, Exception? innerException) + => throw new InvalidOperationException(message, innerException); /// /// Throws a new . @@ -420,7 +438,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowLockRecursionException(string? message, Exception? innerException) => throw new LockRecursionException(message, innerException); + public static T ThrowLockRecursionException(string? message, Exception? innerException) + => throw new LockRecursionException(message, innerException); /// /// Throws a new . @@ -450,7 +469,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowMissingFieldException(string? message, Exception? innerException) => throw new MissingFieldException(message, innerException); + public static T ThrowMissingFieldException(string? message, Exception? innerException) + => throw new MissingFieldException(message, innerException); /// /// Throws a new . @@ -461,7 +481,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowMissingFieldException(string? className, string? fieldName) => throw new MissingFieldException(className, fieldName); + public static T ThrowMissingFieldException(string? className, string? fieldName) + => throw new MissingFieldException(className, fieldName); /// /// Throws a new . @@ -491,7 +512,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowMissingMemberException(string? message, Exception? innerException) => throw new MissingMemberException(message, innerException); + public static T ThrowMissingMemberException(string? message, Exception? innerException) + => throw new MissingMemberException(message, innerException); /// /// Throws a new . @@ -502,7 +524,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowMissingMemberException(string? className, string? memberName) => throw new MissingMemberException(className, memberName); + public static T ThrowMissingMemberException(string? className, string? memberName) + => throw new MissingMemberException(className, memberName); /// /// Throws a new . @@ -532,7 +555,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowMissingMethodException(string? message, Exception? innerException) => throw new MissingMethodException(message, innerException); + public static T ThrowMissingMethodException(string? message, Exception? innerException) + => throw new MissingMethodException(message, innerException); /// /// Throws a new . @@ -543,7 +567,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowMissingMethodException(string? className, string? methodName) => throw new MissingMethodException(className, methodName); + public static T ThrowMissingMethodException(string? className, string? methodName) + => throw new MissingMethodException(className, methodName); /// /// Throws a new . @@ -573,7 +598,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowNotSupportedException(string? message, Exception? innerException) => throw new NotSupportedException(message, innerException); + public static T ThrowNotSupportedException(string? message, Exception? innerException) + => throw new NotSupportedException(message, innerException); /// /// Throws a new . @@ -583,7 +609,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowObjectDisposedException(string? objectName) => throw new ObjectDisposedException(objectName); + public static T ThrowObjectDisposedException(string? objectName) + => throw new ObjectDisposedException(objectName); /// /// Throws a new . @@ -594,7 +621,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowObjectDisposedException(string? objectName, Exception? innerException) => throw new ObjectDisposedException(objectName, innerException); + public static T ThrowObjectDisposedException(string? objectName, Exception? innerException) + => throw new ObjectDisposedException(objectName, innerException); /// /// Throws a new . @@ -605,7 +633,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowObjectDisposedException(string? objectName, string? message) => throw new ObjectDisposedException(objectName, message); + public static T ThrowObjectDisposedException(string? objectName, string? message) + => throw new ObjectDisposedException(objectName, message); /// /// Throws a new . @@ -624,7 +653,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowOperationCanceledException(string? message) => throw new OperationCanceledException(message); + public static T ThrowOperationCanceledException(string? message) + => throw new OperationCanceledException(message); /// /// Throws a new . @@ -635,7 +665,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowOperationCanceledException(string? message, Exception? innerException) => throw new OperationCanceledException(message, innerException); + public static T ThrowOperationCanceledException(string? message, Exception? innerException) + => throw new OperationCanceledException(message, innerException); /// /// Throws a new . @@ -645,7 +676,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowOperationCanceledException(CancellationToken token) => throw new OperationCanceledException(token); + public static T ThrowOperationCanceledException(CancellationToken token) + => throw new OperationCanceledException(token); /// /// Throws a new . @@ -656,7 +688,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowOperationCanceledException(string? message, CancellationToken token) => throw new OperationCanceledException(message, token); + public static T ThrowOperationCanceledException(string? message, CancellationToken token) + => throw new OperationCanceledException(message, token); /// /// Throws a new . @@ -668,7 +701,9 @@ public static partial class ThrowHelper /// Thrown with the specified parameters. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowOperationCanceledException(string? message, Exception? innerException, CancellationToken token) => throw new OperationCanceledException(message, innerException, token); + public static T ThrowOperationCanceledException(string? message, Exception? innerException, + CancellationToken token) + => throw new OperationCanceledException(message, innerException, token); /// /// Throws a new . @@ -687,7 +722,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowPlatformNotSupportedException(string? message) => throw new PlatformNotSupportedException(message); + public static T ThrowPlatformNotSupportedException(string? message) + => throw new PlatformNotSupportedException(message); /// /// Throws a new . @@ -698,7 +734,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowPlatformNotSupportedException(string? message, Exception? innerException) => throw new PlatformNotSupportedException(message, innerException); + public static T ThrowPlatformNotSupportedException(string? message, Exception? innerException) + => throw new PlatformNotSupportedException(message, innerException); /// /// Throws a new . @@ -717,7 +754,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowSynchronizationLockException(string? message) => throw new SynchronizationLockException(message); + public static T ThrowSynchronizationLockException(string? message) + => throw new SynchronizationLockException(message); /// /// Throws a new . @@ -728,7 +766,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowSynchronizationLockException(string? message, Exception? innerException) => throw new SynchronizationLockException(message, innerException); + public static T ThrowSynchronizationLockException(string? message, Exception? innerException) + => throw new SynchronizationLockException(message, innerException); /// /// Throws a new . @@ -758,7 +797,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowTimeoutException(string? message, Exception? innerException) => throw new TimeoutException(message, innerException); + public static T ThrowTimeoutException(string? message, Exception? innerException) + => throw new TimeoutException(message, innerException); /// /// Throws a new . @@ -777,7 +817,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowUnauthorizedAccessException(string? message) => throw new UnauthorizedAccessException(message); + public static T ThrowUnauthorizedAccessException(string? message) + => throw new UnauthorizedAccessException(message); /// /// Throws a new . @@ -788,7 +829,8 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowUnauthorizedAccessException(string? message, Exception? innerException) => throw new UnauthorizedAccessException(message, innerException); + public static T ThrowUnauthorizedAccessException(string? message, Exception? innerException) + => throw new UnauthorizedAccessException(message, innerException); /// /// Throws a new . @@ -839,5 +881,6 @@ public static partial class ThrowHelper /// Thrown with the specified parameter. /// This method always throws, so it actually never returns a value. [DoesNotReturn] - public static T ThrowWin32Exception(string? message, Exception? innerException) => throw new Win32Exception(message, innerException); -} + public static T ThrowWin32Exception(string? message, Exception? innerException) + => throw new Win32Exception(message, innerException); +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/ThrowHelper.cs b/Source/FisheryLib/Diagnostics/ThrowHelper.cs index 5a7f795..ea27bb2 100644 --- a/Source/FisheryLib/Diagnostics/ThrowHelper.cs +++ b/Source/FisheryLib/Diagnostics/ThrowHelper.cs @@ -28,7 +28,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowArrayTypeMismatchException(string? message) => throw new ArrayTypeMismatchException(message); + public static void ThrowArrayTypeMismatchException(string? message) + => throw new ArrayTypeMismatchException(message); /// /// Throws a new . @@ -37,7 +38,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArrayTypeMismatchException(string? message, Exception? innerException) => throw new ArrayTypeMismatchException(message, innerException); + public static void ThrowArrayTypeMismatchException(string? message, Exception? innerException) + => throw new ArrayTypeMismatchException(message, innerException); /// /// Throws a new . @@ -61,7 +63,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArgumentException(string? message, Exception? innerException) => throw new ArgumentException(message, innerException); + public static void ThrowArgumentException(string? message, Exception? innerException) + => throw new ArgumentException(message, innerException); /// /// Throws a new . @@ -70,7 +73,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArgumentException(string? name, string? message) => throw new ArgumentException(message, name); + public static void ThrowArgumentException(string? name, string? message) + => throw new ArgumentException(message, name); /// /// Throws a new . @@ -80,7 +84,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArgumentException(string? name, string? message, Exception? innerException) => throw new ArgumentException(message, name, innerException); + public static void ThrowArgumentException(string? name, string? message, Exception? innerException) + => throw new ArgumentException(message, name, innerException); /// /// Throws a new . @@ -104,7 +109,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArgumentNullException(string? name, Exception? innerException) => throw new ArgumentNullException(name, innerException); + public static void ThrowArgumentNullException(string? name, Exception? innerException) + => throw new ArgumentNullException(name, innerException); /// /// Throws a new . @@ -113,7 +119,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArgumentNullException(string? name, string? message) => throw new ArgumentNullException(name, message); + public static void ThrowArgumentNullException(string? name, string? message) + => throw new ArgumentNullException(name, message); /// /// Throws a new . @@ -137,7 +144,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeException(string? name, Exception? innerException) => throw new ArgumentOutOfRangeException(name, innerException); + public static void ThrowArgumentOutOfRangeException(string? name, Exception? innerException) + => throw new ArgumentOutOfRangeException(name, innerException); /// /// Throws a new . @@ -146,7 +154,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeException(string? name, string? message) => throw new ArgumentOutOfRangeException(name, message); + public static void ThrowArgumentOutOfRangeException(string? name, string? message) + => throw new ArgumentOutOfRangeException(name, message); /// /// Throws a new . @@ -156,7 +165,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowArgumentOutOfRangeException(string? name, object? value, string? message) => throw new ArgumentOutOfRangeException(name, value, message); + public static void ThrowArgumentOutOfRangeException(string? name, object? value, string? message) + => throw new ArgumentOutOfRangeException(name, value, message); /// /// Throws a new . @@ -180,7 +190,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowCOMException(string? message, Exception? innerException) => throw new COMException(message, innerException); + public static void ThrowCOMException(string? message, Exception? innerException) + => throw new COMException(message, innerException); /// /// Throws a new . @@ -213,7 +224,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowExternalException(string? message, Exception? innerException) => throw new ExternalException(message, innerException); + public static void ThrowExternalException(string? message, Exception? innerException) + => throw new ExternalException(message, innerException); /// /// Throws a new . @@ -222,7 +234,8 @@ public static partial class ThrowHelper /// The HRESULT of the error to include. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowExternalException(string? message, int error) => throw new ExternalException(message, error); + public static void ThrowExternalException(string? message, int error) + => throw new ExternalException(message, error); /// /// Throws a new . @@ -246,7 +259,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowFormatException(string? message, Exception? innerException) => throw new FormatException(message, innerException); + public static void ThrowFormatException(string? message, Exception? innerException) + => throw new FormatException(message, innerException); /// /// Throws a new . @@ -261,7 +275,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowInsufficientMemoryException(string? message) => throw new InsufficientMemoryException(message); + public static void ThrowInsufficientMemoryException(string? message) + => throw new InsufficientMemoryException(message); /// /// Throws a new . @@ -270,7 +285,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowInsufficientMemoryException(string? message, Exception? innerException) => throw new InsufficientMemoryException(message, innerException); + public static void ThrowInsufficientMemoryException(string? message, Exception? innerException) + => throw new InsufficientMemoryException(message, innerException); /// /// Throws a new . @@ -294,7 +310,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowInvalidDataException(string? message, Exception? innerException) => throw new InvalidDataException(message, innerException); + public static void ThrowInvalidDataException(string? message, Exception? innerException) + => throw new InvalidDataException(message, innerException); /// /// Throws a new . @@ -318,7 +335,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowInvalidOperationException(string? message, Exception? innerException) => throw new InvalidOperationException(message, innerException); + public static void ThrowInvalidOperationException(string? message, Exception? innerException) + => throw new InvalidOperationException(message, innerException); /// /// Throws a new . @@ -342,7 +360,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowLockRecursionException(string? message, Exception? innerException) => throw new LockRecursionException(message, innerException); + public static void ThrowLockRecursionException(string? message, Exception? innerException) + => throw new LockRecursionException(message, innerException); /// /// Throws a new . @@ -366,7 +385,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowMissingFieldException(string? message, Exception? innerException) => throw new MissingFieldException(message, innerException); + public static void ThrowMissingFieldException(string? message, Exception? innerException) + => throw new MissingFieldException(message, innerException); /// /// Throws a new . @@ -375,7 +395,8 @@ public static partial class ThrowHelper /// The target field being retrieved. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowMissingFieldException(string? className, string? fieldName) => throw new MissingFieldException(className, fieldName); + public static void ThrowMissingFieldException(string? className, string? fieldName) + => throw new MissingFieldException(className, fieldName); /// /// Throws a new . @@ -399,7 +420,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowMissingMemberException(string? message, Exception? innerException) => throw new MissingMemberException(message, innerException); + public static void ThrowMissingMemberException(string? message, Exception? innerException) + => throw new MissingMemberException(message, innerException); /// /// Throws a new . @@ -408,7 +430,8 @@ public static partial class ThrowHelper /// The target member being retrieved. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowMissingMemberException(string? className, string? memberName) => throw new MissingMemberException(className, memberName); + public static void ThrowMissingMemberException(string? className, string? memberName) + => throw new MissingMemberException(className, memberName); /// /// Throws a new . @@ -432,7 +455,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowMissingMethodException(string? message, Exception? innerException) => throw new MissingMethodException(message, innerException); + public static void ThrowMissingMethodException(string? message, Exception? innerException) + => throw new MissingMethodException(message, innerException); /// /// Throws a new . @@ -441,7 +465,8 @@ public static partial class ThrowHelper /// The target method being retrieved. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowMissingMethodException(string? className, string? methodName) => throw new MissingMethodException(className, methodName); + public static void ThrowMissingMethodException(string? className, string? methodName) + => throw new MissingMethodException(className, methodName); /// /// Throws a new . @@ -465,7 +490,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowNotSupportedException(string? message, Exception? innerException) => throw new NotSupportedException(message, innerException); + public static void ThrowNotSupportedException(string? message, Exception? innerException) + => throw new NotSupportedException(message, innerException); /// /// Throws a new . @@ -473,7 +499,8 @@ public static partial class ThrowHelper /// The name of the disposed object. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowObjectDisposedException(string? objectName) => throw new ObjectDisposedException(objectName); + public static void ThrowObjectDisposedException(string? objectName) + => throw new ObjectDisposedException(objectName); /// /// Throws a new . @@ -482,7 +509,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowObjectDisposedException(string? objectName, Exception? innerException) => throw new ObjectDisposedException(objectName, innerException); + public static void ThrowObjectDisposedException(string? objectName, Exception? innerException) + => throw new ObjectDisposedException(objectName, innerException); /// /// Throws a new . @@ -491,7 +519,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowObjectDisposedException(string? objectName, string? message) => throw new ObjectDisposedException(objectName, message); + public static void ThrowObjectDisposedException(string? objectName, string? message) + => throw new ObjectDisposedException(objectName, message); /// /// Throws a new . @@ -506,7 +535,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowOperationCanceledException(string? message) => throw new OperationCanceledException(message); + public static void ThrowOperationCanceledException(string? message) + => throw new OperationCanceledException(message); /// /// Throws a new . @@ -515,7 +545,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowOperationCanceledException(string? message, Exception? innerException) => throw new OperationCanceledException(message, innerException); + public static void ThrowOperationCanceledException(string? message, Exception? innerException) + => throw new OperationCanceledException(message, innerException); /// /// Throws a new . @@ -523,7 +554,8 @@ public static partial class ThrowHelper /// The in use. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowOperationCanceledException(CancellationToken token) => throw new OperationCanceledException(token); + public static void ThrowOperationCanceledException(CancellationToken token) + => throw new OperationCanceledException(token); /// /// Throws a new . @@ -532,7 +564,8 @@ public static partial class ThrowHelper /// The in use. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowOperationCanceledException(string? message, CancellationToken token) => throw new OperationCanceledException(message, token); + public static void ThrowOperationCanceledException(string? message, CancellationToken token) + => throw new OperationCanceledException(message, token); /// /// Throws a new . @@ -542,7 +575,9 @@ public static partial class ThrowHelper /// The in use. /// Thrown with the specified parameters. [DoesNotReturn] - public static void ThrowOperationCanceledException(string? message, Exception? innerException, CancellationToken token) => throw new OperationCanceledException(message, innerException, token); + public static void ThrowOperationCanceledException(string? message, Exception? innerException, + CancellationToken token) + => throw new OperationCanceledException(message, innerException, token); /// /// Throws a new . @@ -557,7 +592,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowPlatformNotSupportedException(string? message) => throw new PlatformNotSupportedException(message); + public static void ThrowPlatformNotSupportedException(string? message) + => throw new PlatformNotSupportedException(message); /// /// Throws a new . @@ -566,7 +602,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowPlatformNotSupportedException(string? message, Exception? innerException) => throw new PlatformNotSupportedException(message, innerException); + public static void ThrowPlatformNotSupportedException(string? message, Exception? innerException) + => throw new PlatformNotSupportedException(message, innerException); /// /// Throws a new . @@ -581,7 +618,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowSynchronizationLockException(string? message) => throw new SynchronizationLockException(message); + public static void ThrowSynchronizationLockException(string? message) + => throw new SynchronizationLockException(message); /// /// Throws a new . @@ -590,7 +628,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowSynchronizationLockException(string? message, Exception? innerException) => throw new SynchronizationLockException(message, innerException); + public static void ThrowSynchronizationLockException(string? message, Exception? innerException) + => throw new SynchronizationLockException(message, innerException); /// /// Throws a new . @@ -614,7 +653,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowTimeoutException(string? message, Exception? innerException) => throw new TimeoutException(message, innerException); + public static void ThrowTimeoutException(string? message, Exception? innerException) + => throw new TimeoutException(message, innerException); /// /// Throws a new . @@ -629,7 +669,8 @@ public static partial class ThrowHelper /// The message to include in the exception. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowUnauthorizedAccessException(string? message) => throw new UnauthorizedAccessException(message); + public static void ThrowUnauthorizedAccessException(string? message) + => throw new UnauthorizedAccessException(message); /// /// Throws a new . @@ -638,7 +679,8 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowUnauthorizedAccessException(string? message, Exception? innerException) => throw new UnauthorizedAccessException(message, innerException); + public static void ThrowUnauthorizedAccessException(string? message, Exception? innerException) + => throw new UnauthorizedAccessException(message, innerException); /// /// Throws a new . @@ -679,5 +721,6 @@ public static partial class ThrowHelper /// The inner to include. /// Thrown with the specified parameter. [DoesNotReturn] - public static void ThrowWin32Exception(string? message, Exception? innerException) => throw new Win32Exception(message, innerException); -} + public static void ThrowWin32Exception(string? message, Exception? innerException) + => throw new Win32Exception(message, innerException); +} \ No newline at end of file diff --git a/Source/FisheryLib/Equality.cs b/Source/FisheryLib/Equality.cs index fe90726..53d1183 100644 --- a/Source/FisheryLib/Equality.cs +++ b/Source/FisheryLib/Equality.cs @@ -12,16 +12,17 @@ namespace FisheryLib; public static class Equality { /// - /// Generic overload of Equals to avoid boxing. Makes use of function pointers for best performance and does not throw on null for reference types. + /// Generic overload of Equals to avoid boxing. Makes use of function pointers for best performance and does not + /// throw on null for reference types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe bool Equals([AllowNull] this T @this, [AllowNull] T other) => FunctionPointers.Equals.Default(@this!, other!); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe bool Equals([AllowNull] this ref T @this, [AllowNull] ref T other) + public static unsafe bool Equals(this ref T @this, ref T other) where T : struct // required by the compiler for 'this ref' - => FunctionPointers.EqualsByRef.Default(ref @this!, ref other!); + => FunctionPointers.EqualsByRef.Default(ref @this, ref other); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe bool EqualsByRef([AllowNull] ref T @this, [AllowNull] ref T other) diff --git a/Source/FisheryLib/FishPatch.cs b/Source/FisheryLib/FishPatch.cs index c33ba8b..42ac7a5 100644 --- a/Source/FisheryLib/FishPatch.cs +++ b/Source/FisheryLib/FishPatch.cs @@ -335,4 +335,5 @@ public abstract class ClassWithFishPatches : IHasFishPatch public virtual FishPatchHolder? PatchHolder { get => _patchHolder; set => _patchHolder = value; } public virtual bool RequiresLoadedGameForPatching => false; private FishPatchHolder? _patchHolder; -}*/ \ No newline at end of file +}*/ + diff --git a/Source/FisheryLib/FishTranspiler.cs b/Source/FisheryLib/FishTranspiler.cs index bb8c282..d8f875a 100644 --- a/Source/FisheryLib/FishTranspiler.cs +++ b/Source/FisheryLib/FishTranspiler.cs @@ -7,11 +7,18 @@ using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection.Emit; +using System.Security; +using JetBrains.Annotations; +using Verse; +// ReSharper disable PossibleMultipleEnumeration namespace FisheryLib; + +[PublicAPI] public static class FishTranspiler { - public struct Container + [PublicAPI] + public readonly struct Container : IEquatable, IEquatable { public Container(OpCode opcode, object? operand = null) { @@ -34,31 +41,37 @@ public static class FishTranspiler } public override string ToString() - => $"{OpCode} {Operand}"; + => $"{OpCode} {Operand switch + { + MemberInfo memberInfo => memberInfo.FullDescription(), + null => "NULL", + _ => Operand.ToString() + }}"; - public CodeInstruction ToInstruction() - => new(OpCode, Operand); + [SecuritySafeCritical] + public CodeInstruction ToInstruction() => new(OpCode, Operand); public Container Store() - => OpCode.LoadsArgument() ? ToStoreArgument() - : new( - OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToStoreField() - : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToStoreLocalVariable() - : OpCode.StoresArgument() ? OpCode - : ThrowHelper.ThrowInvalidOperationException($"Cannot determine Store instruction for {OpCode}"), - Operand); + => OpCode.LoadsArgument() + ? ToStoreArgument() + : new(OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToStoreField() + : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToStoreLocalVariable() + : OpCode.StoresArgument() ? OpCode + : ThrowHelper.ThrowInvalidOperationException( + $"Cannot determine Store instruction for {OpCode}"), + Operand); public Container Load() - => OpCode.StoresArgument() ? ToLoadArgument() - : new( - OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToLoadField() - : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToLoadLocalVariable() - : OpCode.LoadsArgument() ? OpCode - : ThrowHelper.ThrowInvalidOperationException($"Cannot determine Load instruction for {OpCode}"), - Operand); + => OpCode.StoresArgument() + ? ToLoadArgument() + : new(OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToLoadField() + : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToLoadLocalVariable() + : OpCode.LoadsArgument() ? OpCode + : ThrowHelper.ThrowInvalidOperationException( + $"Cannot determine Load instruction for {OpCode}"), + Operand); - private Container ToStoreArgument() - => new(OpCode.ToStoreArgument(), GetIndex()); + private Container ToStoreArgument() => new(OpCode.ToStoreArgument(), GetIndex()); private Container ToLoadArgument() { @@ -66,12 +79,11 @@ public static class FishTranspiler return new(GetLoadArgumentOpCode(index), index > 3 ? index : null); } - public Container Address() - => new(OpCode.ToAddress(), GetIndex()); + public Container Address() => new(OpCode.ToAddress(), GetIndex()); - public CodeInstruction WithLabels(params Label[] labels) - => WithLabels((IEnumerable public int Pops => PopsNone() ? 0 - : PopsOne() ? 1 - : PopsTwo() ? 2 - : PopsThree() ? 3 - : OpCode.Calls() ? GetCallPops() - : OpCode.Branches() ? GetBranchPops() - : throw new NotImplementedException(); + : PopsOne() ? 1 + : PopsTwo() ? 2 + : PopsThree() ? 3 + : OpCode.Calls() ? GetCallPops() + : OpCode.Branches() ? GetBranchPops() + : ThrowHelper.ThrowNotSupportedException($"OpCode { + OpCode} not supported by FishTranspiler.Pops"); /// /// Gets the number of values pushed onto the stack by this instruction /// public int Pushes => PushesNone() ? 0 - : PushesOne() ? 1 - : PushesTwo() ? 2 - : OpCode.Calls() ? GetCallPushes() - : throw new NotImplementedException(); + : PushesOne() ? 1 + : PushesTwo() ? 2 + : OpCode.Calls() ? GetCallPushes() + : ThrowHelper.ThrowNotSupportedException($"OpCode { + OpCode} not supported by FishTranspiler.Pushes"); private bool PopsNone() => OpCode == OpCodes.Nop - || OpCode == OpCodes.Jmp - || OpCode == OpCodes.Ldftn - || OpCode.LoadsArgument() - || OpCode.LoadsConstant() - || OpCode.LoadsStaticField() - || OpCode.LoadsLocalVariable(); + || OpCode == OpCodes.Jmp + || OpCode == OpCodes.Ldftn + || OpCode.LoadsArgument() + || OpCode.LoadsConstant() + || OpCode.LoadsStaticField() + || OpCode.LoadsLocalVariable(); private bool PopsOne() => OpCode == OpCodes.Pop - || OpCode == OpCodes.Initobj - || OpCode == OpCodes.Dup - || OpCode == OpCodes.Isinst - || OpCode == OpCodes.Not - || OpCode == OpCodes.Neg - || OpCode == OpCodes.Ldlen - || OpCode == OpCodes.Newarr - || OpCode == OpCodes.Ldvirtftn - || OpCode.StoresArgument() - || OpCode.StoresStaticField() - || OpCode.LoadsInstanceField() - || OpCode.StoresLocalVariable() - || OpCode.LoadsByRef() - || OpCode.Converts(); + || OpCode == OpCodes.Initobj + || OpCode == OpCodes.Dup + || OpCode == OpCodes.Isinst + || OpCode == OpCodes.Not + || OpCode == OpCodes.Neg + || OpCode == OpCodes.Ldlen + || OpCode == OpCodes.Newarr + || OpCode == OpCodes.Ldvirtftn + || OpCode.StoresArgument() + || OpCode.StoresStaticField() + || OpCode.LoadsInstanceField() + || OpCode.StoresLocalVariable() + || OpCode.LoadsByRef() + || OpCode.Converts(); private bool PopsTwo() => OpCode == OpCodes.Cpobj - || OpCode.StoresInstanceField() - || OpCode.LoadsElement() - || OpCode.StoresByRef() - || OpCode.Compares() - || OpCode.Computes(); + || OpCode.StoresInstanceField() + || OpCode.LoadsElement() + || OpCode.StoresByRef() + || OpCode.Compares() + || OpCode.Computes(); private bool PopsThree() => OpCode == OpCodes.Cpblk - || OpCode == OpCodes.Initblk - || OpCode.StoresElement(); + || OpCode == OpCodes.Initblk + || OpCode.StoresElement(); private int GetCallPops() => OpCode == OpCodes.Calli - || Operand is not MethodInfo methodInfo ? ThrowHelper.ThrowNotSupportedException() - : methodInfo.GetParameters().Length + (methodInfo.IsStatic ? 0 : 1); + || Operand is not MethodInfo methodInfo + ? ThrowHelper.ThrowNotSupportedException() + : methodInfo.GetParameters().Length + (methodInfo.IsStatic ? 0 : 1); private int GetBranchPops() => OpCode == OpCodes.Brtrue - || OpCode == OpCodes.Brtrue_S - || OpCode == OpCodes.Brfalse - || OpCode == OpCodes.Brfalse_S - || OpCode == OpCodes.Switch ? 1 - : OpCode == OpCodes.Br - || OpCode == OpCodes.Br_S ? 0 - : 2; // greater, less, equal, etc + || OpCode == OpCodes.Brtrue_S + || OpCode == OpCodes.Brfalse + || OpCode == OpCodes.Brfalse_S + || OpCode == OpCodes.Switch ? 1 + : OpCode == OpCodes.Br + || OpCode == OpCodes.Br_S ? 0 + : 2; // greater, less, equal, etc private bool PushesNone() => OpCode == OpCodes.Nop - || OpCode == OpCodes.Jmp - || OpCode == OpCodes.Pop - || OpCode == OpCodes.Cpblk - || OpCode == OpCodes.Initblk - || OpCode == OpCodes.Cpobj - || OpCode == OpCodes.Initobj - || OpCode.StoresArgument() - || OpCode.StoresField() - || OpCode.StoresLocalVariable() - || OpCode.StoresElement() - || OpCode.StoresByRef() - || OpCode.Branches(); + || OpCode == OpCodes.Jmp + || OpCode == OpCodes.Pop + || OpCode == OpCodes.Cpblk + || OpCode == OpCodes.Initblk + || OpCode == OpCodes.Cpobj + || OpCode == OpCodes.Initobj + || OpCode.StoresArgument() + || OpCode.StoresField() + || OpCode.StoresLocalVariable() + || OpCode.StoresElement() + || OpCode.StoresByRef() + || OpCode.Branches(); private bool PushesOne() => OpCode == OpCodes.Isinst - || OpCode == OpCodes.Ldlen - || OpCode == OpCodes.Newarr - || OpCode == OpCodes.Newobj - || OpCode == OpCodes.Ldftn - || OpCode == OpCodes.Ldvirtftn - || OpCode.LoadsArgument() - || OpCode.LoadsConstant() - || OpCode.LoadsField() - || OpCode.LoadsLocalVariable() - || OpCode.LoadsElement() - || OpCode.LoadsByRef() - || OpCode.Compares() - || OpCode.Computes() - || OpCode.Converts(); + || OpCode == OpCodes.Ldlen + || OpCode == OpCodes.Newarr + || OpCode == OpCodes.Newobj + || OpCode == OpCodes.Ldftn + || OpCode == OpCodes.Ldvirtftn + || OpCode.LoadsArgument() + || OpCode.LoadsConstant() + || OpCode.LoadsField() + || OpCode.LoadsLocalVariable() + || OpCode.LoadsElement() + || OpCode.LoadsByRef() + || OpCode.Compares() + || OpCode.Computes() + || OpCode.Converts(); - private bool PushesTwo() - => OpCode == OpCodes.Dup; + private bool PushesTwo() => OpCode == OpCodes.Dup; private int GetCallPushes() => OpCode == OpCodes.Calli - || Operand is not MethodInfo methodInfo ? ThrowHelper.ThrowNotSupportedException() - : methodInfo.ReturnType == typeof(void) ? 0 - : 1; + || Operand is not MethodInfo methodInfo ? ThrowHelper.ThrowNotSupportedException() + : methodInfo.ReturnType == typeof(void) ? 0 + : 1; } /// @@ -481,8 +500,11 @@ public static class FishTranspiler Guard.IsNotNull(predicate); var locals = MatchingLocalVariables(method, predicate); - return locals.Any() ? locals.First() - : ThrowHelper.ThrowInvalidOperationException($"No local variable found for predicate {predicate.Method.FullDescription()} and method {method.FullDescription()}"); + return locals.Any() + ? locals.First() + : ThrowHelper.ThrowInvalidOperationException( + $"No local variable found for predicate {predicate.Method.FullDescription()} and method { + method.FullDescription()}"); } /// @@ -490,7 +512,8 @@ public static class FishTranspiler /// /// The MethodBase of the method to search for local variables in /// The predicate used to identify the local variables - public static IEnumerable MatchingLocalVariables(MethodBase method, Predicate predicate) + public static IEnumerable MatchingLocalVariables(MethodBase method, + Predicate predicate) { Guard.IsNotNull(method); Guard.IsNotNull(predicate); @@ -511,8 +534,10 @@ public static class FishTranspiler Guard.IsNotNull(localType); var operands = GetLocalOperandsOrIndices(codes, c => c.Returns(localType)); - return operands.Any() ? LocalVariable(operands.First()) - : ThrowHelper.ThrowInvalidOperationException($"No local variable found with localType {localType.FullDescription()}"); + return operands.Any() + ? LocalVariable(operands.First()) + : ThrowHelper.ThrowInvalidOperationException( + $"No local variable found with localType {localType.FullDescription()}"); } /// @@ -570,8 +595,10 @@ public static class FishTranspiler Guard.IsNotNull(predicate); var locals = StoreMatchingLocalVariables(method, predicate); - return locals.Any() ? locals.First() - : ThrowHelper.ThrowInvalidOperationException($"No local variable found for predicate {predicate.Method.FullDescription()} and method {method.FullDescription()}"); + return locals.Any() + ? locals.First() + : ThrowHelper.ThrowInvalidOperationException( + $"No local variable found for predicate {predicate.Method.FullDescription()} and method {method.FullDescription()}"); } /// @@ -580,7 +607,8 @@ public static class FishTranspiler /// /// The MethodBase of the method to search for local variables in /// The predicate used to identify the local variables - public static IEnumerable StoreMatchingLocalVariables(MethodBase method, Predicate predicate) + public static IEnumerable StoreMatchingLocalVariables(MethodBase method, + Predicate predicate) { Guard.IsNotNull(method); Guard.IsNotNull(predicate); @@ -601,8 +629,10 @@ public static class FishTranspiler Guard.IsNotNull(localType); var operands = GetLocalOperandsOrIndices(codes, c => c.Returns(localType)); - return operands.Any() ? StoreLocalVariable(operands.First()) - : ThrowHelper.ThrowInvalidOperationException($"No local variable found with localType {localType.FullDescription()}"); + return operands.Any() + ? StoreLocalVariable(operands.First()) + : ThrowHelper.ThrowInvalidOperationException( + $"No local variable found with localType {localType.FullDescription()}"); } /// @@ -634,23 +664,39 @@ public static class FishTranspiler /// the local variable list at index. /// /// The index of the local variable - public static Container StoreLocalVariable(int index) => new(GetStoreLocalOpCode(index), GetOperandFromIndex(index)); + public static Container StoreLocalVariable(int index) + => new(GetStoreLocalOpCode(index), GetOperandFromIndex(index)); /// - /// Declares a local variable of the specified type, optionally pinning the object referred - /// to by the variable. Then returns an instruction matching that of StoreLocalVariable. + /// Declares a local variable of the specified type. Then returns an instruction matching that of StoreLocalVariable. /// /// A System.Type object that represents the type of the local variable /// The ILGenerator used for the instruction stream - /// True to pin the object in memory; otherwise, false - public static Container NewLocalVariable(Type localType, ILGenerator generator, bool pinned = false) + public static Container NewLocalVariable(Type localType, ILGenerator generator) { Guard.IsNotNull(localType); Guard.IsNotNull(generator); - return StoreLocalVariable(generator.DeclareLocal(localType, pinned)); + return NewLocalVariable(localType, generator, false); } + /// + /// Declares a local variable of the specified type, pinning the object referred to by the variable, + /// for use with unsafe pointers. Then returns an instruction matching that of StoreLocalVariable. + /// + /// A System.Type object that represents the type of the local variable + /// The ILGenerator used for the instruction stream + public static Container NewFixedLocalVariable(Type localType, ILGenerator generator) + { + Guard.IsNotNull(localType); + Guard.IsNotNull(generator); + + return NewLocalVariable(localType, generator, true); + } + + private static Container NewLocalVariable(Type localType, ILGenerator generator, bool pinned) + => StoreLocalVariable(generator.DeclareLocal(localType, pinned)); + /// /// Pushes a supplied value of type int32 onto the evaluation stack as an int32. /// @@ -683,13 +729,13 @@ public static class FishTranspiler => e.GetTypeCode() switch { TypeCode.SByte - or TypeCode.Byte - or TypeCode.Int16 - or TypeCode.UInt16 - or TypeCode.Int32 - or TypeCode.UInt32 => Constant(System.Convert.ToInt32(e)), + or TypeCode.Byte + or TypeCode.Int16 + or TypeCode.UInt16 + or TypeCode.Int32 + or TypeCode.UInt32 => Constant(System.Convert.ToInt32(e)), TypeCode.Int64 - or TypeCode.UInt64 => Constant(System.Convert.ToInt64(e)), + or TypeCode.UInt64 => Constant(System.Convert.ToInt64(e)), var typeCode => InvalidEnumForConstant(e, typeCode) }; @@ -708,14 +754,15 @@ public static class FishTranspiler public static Container Constant(MemberInfo memberInfo) => Token(memberInfo); /// - /// Pushes a supplied value onto the evaluation stack as an int32, int64, float, double, null reference, RuntimeHandle or a reference to a string literal stored in the metadata. + /// Pushes a supplied value onto the evaluation stack as an int32, int64, float, double, null reference, + /// RuntimeHandle or a reference to a string literal stored in the metadata. /// - /// The value to push onto the evaluation stack - public static Container Constant(object obj) - => obj switch + /// The value to push onto the evaluation stack + public static Container Constant(object value) + => value switch { int intValue => Constant(intValue), - long or ulong => Constant(System.Convert.ToInt64(obj)), + long or ulong => Constant(System.Convert.ToInt64(value)), float floatValue => Constant(floatValue), double doubleValue => Constant(doubleValue), Enum enumValue => Constant(enumValue), @@ -723,12 +770,15 @@ public static class FishTranspiler MemberInfo memberInfo => Token(memberInfo), null => Null, IConvertible convertible => Constant(convertible.ToInt32(CultureInfo.InvariantCulture)), - _ => ThrowHelper.ThrowArgumentException(nameof(obj), $"Type {obj.GetType()} cannot be used for FishTranspiler.Constant") + _ => ThrowHelper.ThrowArgumentException(nameof(value), + $"Type {value.GetType()} cannot be used for FishTranspiler.Constant") }; private static Container InvalidEnumForConstant(Enum e, TypeCode typeCode) => ThrowHelper.ThrowArgumentException( - $"Tried using Enum {e.GetType().FullDescription()} with underlying Type {Enum.GetUnderlyingType(e.GetType()).FullDescription()} (TypeCode: {typeCode}) for FishTranspiler.Constant."); + $"Tried using Enum {e.GetType().FullDescription()} with underlying Type { + Enum.GetUnderlyingType(e.GetType()).FullDescription()} (TypeCode: { + typeCode}) for FishTranspiler.Constant."); /// /// Calls the method indicated by the passed method group. @@ -748,6 +798,7 @@ public static class FishTranspiler /// /// An expression with a single method call /// force a Call OpCode instead of using Callvirt where appropriate + [SecuritySafeCritical] public static Container Call(Expression expression, bool forceNoCallvirt = false) { Guard.IsNotNull(expression); @@ -762,15 +813,21 @@ public static class FishTranspiler /// The name of the type the method is declared in /// The name of the method /// An optional array of parameter types to specify the desired method overload - /// An optional array of generic parameter types to specify the method's generic parameters + /// + /// An optional array of generic parameter types to specify the method's generic parameters + /// /// force a Call OpCode instead of using Callvirt where appropriate - public static Container Call(string assembly, string type, string name, Type[]? parameters = null, Type[]? generics = null, bool forceNoCallvirt = false) + public static Container Call(string assembly, string type, string name, Type[]? parameters = null, + Type[]? generics = null, bool forceNoCallvirt = false) { Guard.IsNotNullOrEmpty(assembly); Guard.IsNotNullOrEmpty(type); Guard.IsNotNullOrEmpty(name); - return Call(Type.GetType($"{type}, {assembly}"), name, parameters, generics, forceNoCallvirt); + return Call( + Type.GetType($"{type}, {assembly}") + ?? ThrowHelper.ThrowArgumentException($"No type named {type} found in assembly {assembly}"), name, + parameters, generics, forceNoCallvirt); } /// @@ -779,14 +836,23 @@ public static class FishTranspiler /// The type the method is declared in /// The name of the method /// An optional array of parameter types to specify the desired method overload - /// An optional array of generic parameter types to specify the method's generic parameters + /// + /// An optional array of generic parameter types to specify the method's generic parameters + /// /// force a Call OpCode instead of using Callvirt where appropriate - public static Container Call(Type type, string name, Type[]? parameters = null, Type[]? generics = null, bool forceNoCallvirt = false) + [SecuritySafeCritical] + public static Container Call(Type type, string name, Type[]? parameters = null, Type[]? generics = null, + bool forceNoCallvirt = false) { Guard.IsNotNull(type); Guard.IsNotNullOrEmpty(name); - return Call(AccessTools.Method(type, name, parameters, generics), forceNoCallvirt); + return Call( + AccessTools.Method(type, name, parameters, generics) + ?? ThrowHelper.ThrowArgumentException($"No method found with type {type}, name { + name}{(parameters != null ? $", parameters: {parameters.ToStringSafeEnumerable()}" : "")}{ + (generics != null ? $", generics: {generics.ToStringSafeEnumerable()}" : "")}"), + forceNoCallvirt); } /// @@ -799,7 +865,10 @@ public static class FishTranspiler { Guard.IsNotNull(method); - return new(method.IsStatic || forceNoCallvirt ? OpCodes.Call : OpCodes.Callvirt, method); + return new( + method.IsStatic || (method.DeclaringType?.IsValueType ?? false) || forceNoCallvirt + ? OpCodes.Call + : OpCodes.Callvirt, method); } /// @@ -810,6 +879,7 @@ public static class FishTranspiler /// The type the field is declared in /// The name of the field /// No field found for the specified type and name + [SecuritySafeCritical] public static Container Field(Type type, string name) { Guard.IsNotNull(type); @@ -818,7 +888,8 @@ public static class FishTranspiler var field = AccessTools.Field(type, name); return field != null ? new(field.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, field) - : ThrowHelper.ThrowMissingFieldException($"FishTranspiler.LoadField failed to find a field at {type.FullDescription()}:{name}"); + : ThrowHelper.ThrowMissingFieldException( + $"FishTranspiler.LoadField failed to find a field at {type.FullDescription()}:{name}"); } /// @@ -842,6 +913,7 @@ public static class FishTranspiler /// The type the field is declared in /// The name of the field /// No field found for the specified type and name + [SecuritySafeCritical] public static Container FieldAddress(Type type, string name) { Guard.IsNotNull(type); @@ -850,7 +922,8 @@ public static class FishTranspiler var field = AccessTools.Field(type, name); return field != null ? new(field.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldflda, field) - : ThrowHelper.ThrowMissingFieldException($"FishTranspiler.LoadFieldAddress failed to find a field at {type.FullDescription()}:{name}"); + : ThrowHelper.ThrowMissingFieldException( + $"FishTranspiler.LoadFieldAddress failed to find a field at {type.FullDescription()}:{name}"); } /// @@ -874,6 +947,7 @@ public static class FishTranspiler /// The type the field is declared in /// The name of the field /// No field found for the specified type and name + [SecuritySafeCritical] public static Container StoreField(Type type, string name) { Guard.IsNotNull(type); @@ -882,7 +956,8 @@ public static class FishTranspiler var field = AccessTools.Field(type, name); return field != null ? new(field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, field) - : ThrowHelper.ThrowMissingFieldException($"FishTranspiler.StoreField failed to find a field at {type.FullDescription()}:{name}"); + : ThrowHelper.ThrowMissingFieldException( + $"FishTranspiler.StoreField failed to find a field at {type.FullDescription()}:{name}"); } /// @@ -921,6 +996,7 @@ public static class FishTranspiler /// The name of the property /// force a Call OpCode instead of using Callvirt where appropriate /// No property found for the specified type and name + [SecuritySafeCritical] public static Container PropertyGetter(Type type, string name, bool forceNoCallvirt = false) { Guard.IsNotNull(type); @@ -929,7 +1005,9 @@ public static class FishTranspiler var method = AccessTools.PropertyGetter(type, name); return method != null ? Call(method, forceNoCallvirt) - : ThrowHelper.ThrowMissingMethodException($"FishTranspiler.CallPropertyGetter failed to find a property getter at {type.FullDescription()}:{name}"); + : ThrowHelper.ThrowMissingMethodException( + $"FishTranspiler.CallPropertyGetter failed to find a property getter at { + type.FullDescription()}:{name}"); } /// @@ -945,7 +1023,9 @@ public static class FishTranspiler var method = propertyInfo.GetMethod; return method != null ? Call(method, forceNoCallvirt) - : ThrowHelper.ThrowMissingMethodException($"FishTranspiler.CallPropertyGetter failed to find a property getter at {propertyInfo.DeclaringType.FullDescription()}:{propertyInfo.Name}"); + : ThrowHelper.ThrowMissingMethodException( + $"FishTranspiler.CallPropertyGetter failed to find a property getter at { + propertyInfo.DeclaringType.FullDescription()}:{propertyInfo.Name}"); } /// @@ -955,6 +1035,7 @@ public static class FishTranspiler /// The name of the property /// force a Call OpCode instead of using Callvirt where appropriate /// No property found with specified type and name + [SecuritySafeCritical] public static Container PropertySetter(Type type, string name, bool forceNoCallvirt = false) { Guard.IsNotNull(type); @@ -963,7 +1044,9 @@ public static class FishTranspiler var method = AccessTools.PropertySetter(type, name); return method != null ? Call(method, forceNoCallvirt) - : ThrowHelper.ThrowMissingMethodException($"FishTranspiler.CallPropertySetter failed to find a property setter at {type.FullDescription()}:{name}"); + : ThrowHelper.ThrowMissingMethodException( + $"FishTranspiler.CallPropertySetter failed to find a property setter at { + type.FullDescription()}:{name}"); } /// @@ -979,13 +1062,15 @@ public static class FishTranspiler var method = propertyInfo.SetMethod; return method != null ? Call(method, forceNoCallvirt) - : ThrowHelper.ThrowMissingMethodException($"FishTranspiler.CallPropertySetter failed to find a property setter at {propertyInfo.DeclaringType.FullDescription()}:{propertyInfo.Name}"); + : ThrowHelper.ThrowMissingMethodException( + $"FishTranspiler.CallPropertySetter failed to find a property setter at { + propertyInfo.DeclaringType.FullDescription()}:{propertyInfo.Name}"); } /// /// Constrains the type on which a virtual method call is made. Normally used for generics. /// - /// The type to constrait to + /// The type to constrain to public static Container Constrained() => Constrained(typeof(T)); /// @@ -1013,15 +1098,18 @@ public static class FishTranspiler /// /// The type of the new object /// An optional array of parameter types to specify the desired constructor overload - /// Whether to search for static or instance constructors public static Container New(Type type, Type[]? parameters = null) { Guard.IsNotNull(type); return typeof(Array).IsAssignableFrom(type) ? new(OpCodes.Newarr, type.GetElementType()) - : (parameters is null || parameters.Length == 0) && type.IsValueType ? new(OpCodes.Initobj, type) - : New(AccessTools.Constructor(type, parameters)); + : type.IsValueType + && (parameters is null || parameters.Length == 0) + && !Array.Exists(type.GetConstructors(AccessTools.allDeclared & ~BindingFlags.Static), + static c => c.GetParameters().Length == 0) + ? new(OpCodes.Initobj, type) + : New(Reflection.MatchingConstructor(type, parameters, throwOnFailure: true)!); } /// @@ -1104,6 +1192,18 @@ public static class FishTranspiler /// The label attached to the target instruction public static Container IfNotNull(Label label) => new(OpCodes.Brtrue, label); + /// + /// Unconditionally transfers control to a target instruction. + /// + /// The label attached to the target instruction + public static Container GoTo(Label label) => new(OpCodes.Br, label); + + /// + /// Unconditionally transfers control to a target instruction. Short form for short jumps. + /// + /// The label attached to the target instruction + public static Container GoTo_Short(Label label) => new(OpCodes.Br_S, label); + /// /// Transfers control to a target instruction if two values are equal. /// Short form for short jumps. @@ -1117,6 +1217,19 @@ public static class FishTranspiler /// The label attached to the target instruction public static Container IfEqual(Label label) => new(OpCodes.Beq, label); + /// + /// Transfers control to a target instruction if two values are not equal or unordered. + /// Short form for short jumps. + /// + /// The label attached to the target instruction + public static Container IfNotEqualOrUnordered_Short(Label label) => new(OpCodes.Bne_Un_S, label); + + /// + /// Transfers control to a target instruction if two values are not equal or unordered. + /// + /// The label attached to the target instruction + public static Container IfNotEqualOrUnordered(Label label) => new(OpCodes.Bne_Un, label); + /// /// Transfers control to a target instruction if the first value is /// greater than the second value. Short form for short jumps. @@ -1131,6 +1244,20 @@ public static class FishTranspiler /// The label attached to the target instruction public static Container IfGreaterThan(Label label) => new(OpCodes.Bgt, label); + /// + /// Transfers control to a target instruction if the first value is + /// greater than the second value or if any value is unordered. Short form for short jumps. + /// + /// The label attached to the target instruction + public static Container IfGreaterThanOrUnordered_Short(Label label) => new(OpCodes.Bgt_Un_S, label); + + /// + /// Transfers control to a target instruction if the first value is + /// greater than the second value or if any value is unordered. + /// + /// The label attached to the target instruction + public static Container IfGreaterThanOrUnordered(Label label) => new(OpCodes.Bgt_Un, label); + /// /// Transfers control to a target instruction if the first value is /// greater than or equal to the second value. Short form for short jumps. @@ -1145,6 +1272,21 @@ public static class FishTranspiler /// The label attached to the target instruction public static Container IfGreaterThanOrEqual(Label label) => new(OpCodes.Bge, label); + /// + /// Transfers control to a target instruction if the first value is + /// greater than or equal to the second value or if any value is unordered. + /// Short form for short jumps. + /// + /// The label attached to the target instruction + public static Container IfGreaterThanOrEqualOrUnordered_Short(Label label) => new(OpCodes.Bge_Un_S, label); + + /// + /// Transfers control to a target instruction if the first value is + /// greater than or equal to the second value or if any value is unordered. + /// + /// The label attached to the target instruction + public static Container IfGreaterThanOrEqualOrUnordered(Label label) => new(OpCodes.Bge_Un, label); + /// /// Transfers control to a target instruction if the first value is /// less than the second value. Short form for short jumps. @@ -1159,6 +1301,21 @@ public static class FishTranspiler /// The label attached to the target instruction public static Container IfLessThan(Label label) => new(OpCodes.Blt, label); + /// + /// Transfers control to a target instruction if the first value is + /// less than the second value or if any value is unordered. + /// Short form for short jumps. + /// + /// The label attached to the target instruction + public static Container IfLessThanOrUnordered_Short(Label label) => new(OpCodes.Blt_Un_S, label); + + /// + /// Transfers control to a target instruction if the first value is + /// less than the second value or if any value is unordered. + /// + /// The label attached to the target instruction + public static Container IfLessThanOrUnordered(Label label) => new(OpCodes.Blt_Un, label); + /// /// Transfers control to a target instruction if the first value is /// less than or equal to the second value. Short form for short jumps. @@ -1173,6 +1330,32 @@ public static class FishTranspiler /// The label attached to the target instruction public static Container IfLessThanOrEqual(Label label) => new(OpCodes.Ble, label); + /// + /// Transfers control to a target instruction if the first value is + /// less than or equal to the second value or if any value is unordered. + /// Short form for short jumps. + /// + /// The label attached to the target instruction + public static Container IfLessThanOrEqualOrUnordered_Short(Label label) => new(OpCodes.Ble_Un_S, label); + + /// + /// Transfers control to a target instruction if the first value is + /// less than or equal to the second value or if any value is unordered. + /// + /// The label attached to the target instruction + public static Container IfLessThanOrEqualOrUnordered(Label label) => new(OpCodes.Ble_Un, label); + + /// + /// Implements a jump table. + /// + public static Container Switch(params Label[] labels) + { + Guard.IsNotNull(labels); + Guard.HasSizeGreaterThan(labels, 0); + + return new(OpCodes.Switch, labels); + } + /// /// Loads a value of the specified type onto the evaluation stack indirectly or copies /// the value type object pointed to by an address to the top of the evaluation stack. @@ -1185,6 +1368,7 @@ public static class FishTranspiler /// the value type object pointed to by an address to the top of the evaluation stack. /// /// The object's type + [SecuritySafeCritical] public static Container LoadByRef(Type? type) { if (type is null) @@ -1194,7 +1378,7 @@ public static class FishTranspiler type = type.GetElementType(); return AccessTools.IsStruct(type) - ? LoadObject(type) + ? LoadObject(type!) : LoadIndirectly(type); } @@ -1212,6 +1396,7 @@ public static class FishTranspiler /// memory address. /// /// The object's type + [SecuritySafeCritical] public static Container StoreByRef(Type? type) { if (type is null) @@ -1221,7 +1406,7 @@ public static class FishTranspiler type = type.GetElementType(); return AccessTools.IsStruct(type) - ? StoreObject(type) + ? StoreObject(type!) : StoreIndirectly(type); } @@ -1245,7 +1430,10 @@ public static class FishTranspiler return type.IsValueType ? new(OpCodes.Ldobj, type) - : ThrowHelper.ThrowArgumentException($"Type ({type}) for FishTranspiler.LoadObject must be a ValueType. Use LoadByRef or LoadIndirectly for primitive and reference types.", nameof(type)); + : ThrowHelper.ThrowArgumentException( + $"Type ({type}) for FishTranspiler.LoadObject must be a ValueType. Use LoadByRef or " + + "LoadIndirectly for primitive and reference types.", + nameof(type)); } /// @@ -1268,19 +1456,22 @@ public static class FishTranspiler return type.IsValueType ? new(OpCodes.Stobj, type) - : ThrowHelper.ThrowArgumentException($"Type ({type}) for FishTranspiler.StoreObject must be a ValueType. Use StoreByRef or StoreIndirectly for primitive and reference types.", nameof(type)); + : ThrowHelper.ThrowArgumentException( + $"Type ({type}) for FishTranspiler.StoreObject must be a ValueType. Use StoreByRef or " + + "StoreIndirectly for primitive and reference types.", + nameof(type)); } /// /// Converts a value type to an object reference (type O). /// - /// The object's type + /// The type of the value public static Container Box() => new(OpCodes.Box, typeof(T)); /// /// Converts a value type to an object reference (type O). /// - /// The object's type + /// The type of the value /// type is null /// type is not a ValueType public static Container Box(Type type) @@ -1289,50 +1480,90 @@ public static class FishTranspiler return type.IsValueType ? new(OpCodes.Box, type) - : ThrowHelper.ThrowArgumentException($"Type ({type}) for FishTranspiler.Box must be a ValueType.", nameof(type)); + : ThrowHelper.ThrowArgumentException( + $"Type ({type}) for FishTranspiler.Box must be a ValueType.", nameof(type)); } + /// - /// Converts the boxed representation of a value type to its unboxed form. + /// Converts the boxed representation of a value type to its unboxed form, pushing an address to the box object's + /// held value to the stack. Implemented using the Unbox instruction. /// /// The object's type - public static Container Unbox() => Unbox(typeof(T)); + public static Container UnboxAddress() => UnboxAddress(typeof(T)); /// - /// Converts the boxed representation of a value type to its unboxed form. + /// Converts the boxed representation of a value type to its unboxed form, pushing an address to the box object's + /// held value to the stack. Implemented using the Unbox instruction. /// /// The object's type /// type is null /// type is not a ValueType - public static Container Unbox(Type type) + public static Container UnboxAddress(Type type) { Guard.IsNotNull(type); return type.IsValueType ? new(OpCodes.Unbox, type) - : ThrowHelper.ThrowArgumentException($"Type ({type}) for FishTranspiler.Unbox must be a ValueType.", nameof(type)); + : ThrowHelper.ThrowArgumentException( + $"Type ({type}) for FishTranspiler.UnboxAddress must be a ValueType.", nameof(type)); } /// - /// Converts the boxed representation of a type specified in the instruction to its - /// unboxed form. + /// Converts the boxed representation of a value type to its unboxed form, pushing an address to the box object's + /// held value to the stack. Implemented using the Unbox instruction. /// /// The object's type - public static Container UnboxAny() => UnboxAny(typeof(T)); + [Obsolete("Renamed to UnboxAddress for clarity")] + public static Container Unbox() => UnboxAddress(); /// - /// Converts the boxed representation of a type specified in the instruction to its - /// unboxed form. + /// Converts the boxed representation of a value type to its unboxed form, pushing an address to the box object's + /// held value to the stack. Implemented using the Unbox instruction. /// /// The object's type /// type is null - public static Container UnboxAny(Type type) + /// type is not a ValueType + [Obsolete("Renamed to UnboxAddress for clarity")] + public static Container Unbox(Type type) => UnboxAddress(type); + + /// + /// Converts the boxed representation of a type specified in the instruction to its unboxed form, pushing the value + /// to the stack. Implemented using the UnboxAny instruction. + /// + /// The object's type + public static Container UnboxValue() => UnboxValue(typeof(T)); + + /// + /// Converts the boxed representation of a type specified in the instruction to its unboxed form, pushing the value + /// to the stack. Implemented using the UnboxAny instruction. + /// + /// The object's type + /// type is null + public static Container UnboxValue(Type type) { Guard.IsNotNull(type); return new(OpCodes.Unbox_Any, type); } + /// + /// Converts the boxed representation of a type specified in the instruction to its unboxed form, pushing the value + /// to the stack. Implemented using the UnboxAny instruction. + /// + /// The object's type + [Obsolete("Renamed to UnboxValue for clarity")] + public static Container UnboxAny() => UnboxValue(); + + /// + /// Converts the boxed representation of a type specified in the instruction to its unboxed form, pushing the value + /// to the stack. Implemented using the UnboxAny instruction. + /// + /// The object's type + /// type is null + [Obsolete("Renamed to UnboxValue for clarity")] + public static Container UnboxAny(Type type) => UnboxValue(type); + /// /// Loads the current instance onto the evaluation stack. /// @@ -1386,12 +1617,14 @@ public static class FishTranspiler public static Container MultiplyChecked => new(OpCodes.Mul_Ovf); /// - /// Multiplies two unsigned integer values, performs an overflow check, and pushes the result onto the evaluation stack. + /// Multiplies two unsigned integer values, performs an overflow check, and pushes the result onto the evaluation + /// stack. /// public static Container MultiplyCheckedUnsigned => new(OpCodes.Mul_Ovf_Un); /// - /// Divides two values and pushes the result as a floating-point (type F) or quotient (type int32) onto the evaluation stack. + /// Divides two values and pushes the result as a floating-point (type F) or quotient (type int32) onto the + /// evaluation stack. /// public static Container Divide => new(OpCodes.Div); @@ -1406,28 +1639,89 @@ public static class FishTranspiler public static Container Subtract => new(OpCodes.Sub); /// - /// Subtracts one integer value from another, performs an overflow check, and pushes the result onto the evaluation stack. + /// Subtracts one integer value from another, performs an overflow check, and pushes the result onto the evaluation + /// stack. /// public static Container SubtractChecked => new(OpCodes.Sub_Ovf); /// - /// Subtracts one unsigned integer value from another, performs an overflow check, and pushes the result onto the evaluation stack. + /// Subtracts one unsigned integer value from another, performs an overflow check, and pushes the result onto the + /// evaluation stack. /// public static Container SubtractCheckedUnsigned => new(OpCodes.Sub_Ovf_Un); + /// + /// Divides two values and pushes the remainder onto the evaluation stack. + /// + public static Container Remainder => new(OpCodes.Rem); + + /// + /// Divides two unsigned values and pushes the remainder onto the evaluation stack. + /// + public static Container RemainderUnsigned => new(OpCodes.Rem_Un); + + /// + /// Computes the bitwise AND of two values and pushes the result onto the evaluation + /// stack. + /// + public static Container And => new(OpCodes.And); + + /// + /// Compute the bitwise complement of the two integer values on top of the stack + /// and pushes the result onto the evaluation stack. + /// + public static Container Or => new(OpCodes.Or); + + /// + /// Computes the bitwise XOR of the top two values on the evaluation stack, pushing + /// the result onto the evaluation stack. + /// + public static Container Xor => new(OpCodes.Xor); + + /// + /// Shifts an integer value to the left (in zeroes) by a specified number of bits, + /// pushing the result onto the evaluation stack. + /// + public static Container LeftShift => new(OpCodes.Shl); + + /// + /// Shifts an integer value (in sign) to the right by a specified number of bits, + /// pushing the result onto the evaluation stack. + /// + public static Container RightShift => new(OpCodes.Shr); + + /// + /// Shifts an unsigned integer value (in zeroes) to the right by a specified number + /// of bits, pushing the result onto the evaluation stack. + /// + public static Container RightShiftUnsigned => new(OpCodes.Shr_Un); + + /// + /// Negates a value and pushes the result onto the evaluation stack. + /// + public static Container Negate => new(OpCodes.Neg); + + /// + /// Computes the bitwise complement of the integer value on top of the stack and + /// pushes the result onto the evaluation stack as the same type. + /// + public static Container Not => new(OpCodes.Not); + /// /// Copies a specified number bytes from a source address to a destination address. /// public static Container CopyBlock => new(OpCodes.Cpblk); /// - /// Copies the value type located at the address of an object (type &, or native int) to the address of the destination object (type &, or native int). + /// Copies the value type located at the address of an object (type &, or native int) to the address of the + /// destination object (type &, or native int). /// /// The type of the value public static Container CopyObject() => CopyObject(typeof(T)); /// - /// Copies the value type located at the address of an object (type &, or native int) to the address of the destination object (type &, or native int). + /// Copies the value type located at the address of an object (type &, or native int) to the address of the + /// destination object (type &, or native int). /// /// The type of the value public static Container CopyObject(Type type) @@ -1449,18 +1743,26 @@ public static class FishTranspiler /// The type of the value public static Container LoadIndirectly(Type? type) => new(type is null ? OpCodes.Ldind_Ref - : type.IsPointer ? OpCodes.Ldind_I - : type.IsEnum ? OpCodes.Ldind_I4 - : type == typeof(sbyte) || type == typeof(bool) ? OpCodes.Ldind_I1 - : type == typeof(short) ? OpCodes.Ldind_I2 - : type == typeof(int) ? OpCodes.Ldind_I4 - : type == typeof(long) || type == typeof(ulong) ? OpCodes.Ldind_I8 - : type == typeof(float) ? OpCodes.Ldind_R4 - : type == typeof(double) ? OpCodes.Ldind_R8 - : type == typeof(byte) ? OpCodes.Ldind_U1 - : type == typeof(ushort) || type == typeof(char) ? OpCodes.Ldind_U2 - : type == typeof(uint) ? OpCodes.Ldind_U4 - : OpCodes.Ldind_Ref); + : type.IsPointer ? OpCodes.Ldind_I + : type.IsEnum ? OpCodes.Ldind_I4 + : _loadIndirectlyOpCodesByType.TryGetValue(type, out var value) ? value + : OpCodes.Ldind_Ref); + + private static readonly Dictionary _loadIndirectlyOpCodesByType = new() + { + { typeof(sbyte), OpCodes.Ldind_I1 }, + { typeof(bool), OpCodes.Ldind_I1 }, + { typeof(short), OpCodes.Ldind_I2 }, + { typeof(int), OpCodes.Ldind_I4 }, + { typeof(long), OpCodes.Ldind_I8 }, + { typeof(ulong), OpCodes.Ldind_I8 }, + { typeof(float), OpCodes.Ldind_R4 }, + { typeof(double), OpCodes.Ldind_R8 }, + { typeof(byte), OpCodes.Ldind_U1 }, + { typeof(ushort), OpCodes.Ldind_U2 }, + { typeof(char), OpCodes.Ldind_U2 }, + { typeof(uint), OpCodes.Ldind_U4 } + }; /// /// Stores a value of the specified type at a supplied address. @@ -1474,15 +1776,26 @@ public static class FishTranspiler /// The type of the value public static Container StoreIndirectly(Type? type) => new(type is null ? OpCodes.Stind_Ref - : type.IsPointer ? OpCodes.Stind_I - : type.IsEnum ? OpCodes.Stind_I4 - : type == typeof(sbyte) || type == typeof(byte) || type == typeof(bool) ? OpCodes.Stind_I1 - : type == typeof(short) || type == typeof(ushort) || type == typeof(char) ? OpCodes.Stind_I2 - : type == typeof(int) || type == typeof(uint) ? OpCodes.Stind_I4 - : type == typeof(long) || type == typeof(ulong) ? OpCodes.Stind_I8 - : type == typeof(float) ? OpCodes.Stind_R4 - : type == typeof(double) ? OpCodes.Stind_R8 - : OpCodes.Stind_Ref); + : type.IsPointer ? OpCodes.Stind_I + : type.IsEnum ? OpCodes.Stind_I4 + : _storeIndirectlyOpCodesByType.TryGetValue(type, out var value) ? value + : OpCodes.Stind_Ref); + + private static readonly Dictionary _storeIndirectlyOpCodesByType = new() + { + { typeof(sbyte), OpCodes.Stind_I1 }, + { typeof(byte), OpCodes.Stind_I1 }, + { typeof(bool), OpCodes.Stind_I1 }, + { typeof(short), OpCodes.Stind_I2 }, + { typeof(ushort), OpCodes.Stind_I2 }, + { typeof(char), OpCodes.Stind_I2 }, + { typeof(int), OpCodes.Stind_I4 }, + { typeof(uint), OpCodes.Stind_I4 }, + { typeof(long), OpCodes.Stind_I8 }, + { typeof(ulong), OpCodes.Stind_I8 }, + { typeof(float), OpCodes.Stind_R4 }, + { typeof(double), OpCodes.Stind_R8 } + }; /// /// Replaces the array element at a given index with the value on the evaluation @@ -1498,15 +1811,24 @@ public static class FishTranspiler /// The element's type public static Container StoreElement(Type? type) => type is null ? new(OpCodes.Stelem_Ref) - : type.IsPointer ? new(OpCodes.Stelem_I) - : !type.IsValueType ? new(OpCodes.Stelem_Ref) - : type == typeof(sbyte) || type == typeof(byte) ? new(OpCodes.Stelem_I1) - : type == typeof(short) || type == typeof(ushort) ? new(OpCodes.Stelem_I2) - : type == typeof(int) || type == typeof(uint) ? new(OpCodes.Stelem_I4) - : type == typeof(long) || type == typeof(ulong) ? new(OpCodes.Stelem_I8) - : type == typeof(float) ? new(OpCodes.Stelem_R4) - : type == typeof(double) ? new(OpCodes.Stelem_R8) - : new(OpCodes.Stelem, type); + : type.IsPointer ? new(OpCodes.Stelem_I) + : !type.IsValueType ? new(OpCodes.Stelem_Ref) + : _storeElementOpCodesByType.TryGetValue(type, out var value) ? new(value) + : new(OpCodes.Stelem, type); + + private static readonly Dictionary _storeElementOpCodesByType = new() + { + { typeof(sbyte), OpCodes.Stelem_I1 }, + { typeof(byte), OpCodes.Stelem_I1 }, + { typeof(short), OpCodes.Stelem_I2 }, + { typeof(ushort), OpCodes.Stelem_I2 }, + { typeof(int), OpCodes.Stelem_I4 }, + { typeof(uint), OpCodes.Stelem_I4 }, + { typeof(long), OpCodes.Stelem_I8 }, + { typeof(ulong), OpCodes.Stelem_I8 }, + { typeof(float), OpCodes.Stelem_R4 }, + { typeof(double), OpCodes.Stelem_R8 } + }; /// /// Loads the element at a specified array index onto the top of the evaluation stack @@ -1520,20 +1842,26 @@ public static class FishTranspiler /// as the type specified in the instruction. /// /// The element's type - public static Container LoadElement(Type type) + public static Container LoadElement(Type? type) => type is null ? new(OpCodes.Ldelem_Ref) - : type.IsPointer ? new(OpCodes.Ldelem_I) - : !type.IsValueType ? new(OpCodes.Ldelem_Ref) - : type == typeof(sbyte) ? new(OpCodes.Ldelem_I1) - : type == typeof(short) ? new(OpCodes.Ldelem_I2) - : type == typeof(int) ? new(OpCodes.Ldelem_I4) - : type == typeof(long) || type == typeof(ulong) ? new(OpCodes.Ldelem_I8) - : type == typeof(float) ? new(OpCodes.Ldelem_R4) - : type == typeof(double) ? new(OpCodes.Ldelem_R8) - : type == typeof(byte) ? new(OpCodes.Ldelem_U1) - : type == typeof(ushort) ? new(OpCodes.Ldelem_U2) - : type == typeof(uint) ? new(OpCodes.Ldelem_U4) - : new(OpCodes.Ldelem, type); + : type.IsPointer ? new(OpCodes.Ldelem_I) + : !type.IsValueType ? new(OpCodes.Ldelem_Ref) + : _loadElementOpCodesByType.TryGetValue(type, out var value) ? new(value) + : new(OpCodes.Ldelem, type); + + private static readonly Dictionary _loadElementOpCodesByType = new() + { + { typeof(sbyte), OpCodes.Ldelem_I1 }, + { typeof(short), OpCodes.Ldelem_I2 }, + { typeof(int), OpCodes.Ldelem_I4 }, + { typeof(long), OpCodes.Ldelem_I8 }, + { typeof(ulong), OpCodes.Ldelem_I8 }, + { typeof(float), OpCodes.Ldelem_R4 }, + { typeof(double), OpCodes.Ldelem_R8 }, + { typeof(byte), OpCodes.Ldelem_U1 }, + { typeof(ushort), OpCodes.Ldelem_U2 }, + { typeof(uint), OpCodes.Ldelem_U4 } + }; /// /// Loads the address of the array element at a specified array index onto the top @@ -1554,6 +1882,12 @@ public static class FishTranspiler return new(OpCodes.Ldelema, type); } + /// + /// Pushes the number of elements of a zero-based, one-dimensional array onto the + /// evaluation stack. + /// + public static Container Length => new(OpCodes.Ldlen); + /// /// Converts a metadata token to its runtime representation, pushing it onto the /// evaluation stack. @@ -1642,28 +1976,34 @@ public static class FishTranspiler { Guard.IsNotNull(type, nameof(type)); - return new( - !type.IsPrimitive || type == typeof(char) ? ThrowHelper.ThrowArgumentException("Convert expects a non-character primitive type", nameof(type)) - : type == typeof(byte) ? OpCodes.Conv_U1 - : type == typeof(sbyte) || type == typeof(bool) ? OpCodes.Conv_I1 - : type == typeof(short) ? OpCodes.Conv_I2 - : type == typeof(ushort) ? OpCodes.Conv_U2 - : type == typeof(int) ? OpCodes.Conv_I4 - : type == typeof(uint) ? OpCodes.Conv_U4 - : type == typeof(long) ? OpCodes.Conv_I8 - : type == typeof(ulong) ? OpCodes.Conv_U8 - : type == typeof(IntPtr) ? OpCodes.Conv_I - : type == typeof(UIntPtr) ? OpCodes.Conv_U - : type == typeof(float) ? OpCodes.Conv_R4 - : type == typeof(double) ? OpCodes.Conv_R8 - : ThrowHelper.ThrowArgumentException($"Type {type.FullDescription()} cannot be converted to")); + return new(!type.IsPrimitive || type == typeof(char) + ? ThrowHelper.ThrowArgumentException("Convert expects a non-character primitive type", nameof(type)) + : ConvertOpCodesByType.TryGetValue(type, out var value) ? value + : ThrowHelper.ThrowArgumentException( + $"Type {type.FullDescription()} cannot be converted to")); } + public static readonly Dictionary ConvertOpCodesByType = new() + { + { typeof(byte), OpCodes.Conv_U1 }, + { typeof(sbyte), OpCodes.Conv_I1 }, + { typeof(bool), OpCodes.Conv_I1 }, + { typeof(short), OpCodes.Conv_I2 }, + { typeof(ushort), OpCodes.Conv_U2 }, + { typeof(int), OpCodes.Conv_I4 }, + { typeof(uint), OpCodes.Conv_U4 }, + { typeof(long), OpCodes.Conv_I8 }, + { typeof(ulong), OpCodes.Conv_U8 }, + { typeof(IntPtr), OpCodes.Conv_I }, + { typeof(UIntPtr), OpCodes.Conv_U }, + { typeof(float), OpCodes.Conv_R4 }, + { typeof(double), OpCodes.Conv_R8 } + }; + /// /// Converts the primitive value on top of the evaluation stack to float32 as if it were unsigned. /// - public static Container ConvertUnsignedToFloat() - => new(OpCodes.Conv_R_Un); + public static Container ConvertUnsignedToFloat() => new(OpCodes.Conv_R_Un); /// /// Converts the signed value on top of the evaluation stack to the given non-character primitive @@ -1683,23 +2023,35 @@ public static class FishTranspiler { Guard.IsNotNull(type); - return new( - !type.IsPrimitive || type == typeof(char) ? ThrowHelper.ThrowArgumentException("ConvertWithOverflowCheck expects a non-character primitive type") - : type == typeof(float) ? ThrowHelper.ThrowInvalidOperationException("There is no operation for converting to a float with overflow checking") - : type == typeof(double) ? ThrowHelper.ThrowInvalidOperationException("There is no operation for converting to a double with overflow checking") - : type == typeof(byte) ? OpCodes.Conv_Ovf_U1 - : type == typeof(sbyte) || type == typeof(bool) ? OpCodes.Conv_Ovf_I1 - : type == typeof(short) ? OpCodes.Conv_Ovf_I2 - : type == typeof(ushort) ? OpCodes.Conv_Ovf_U2 - : type == typeof(int) ? OpCodes.Conv_Ovf_I4 - : type == typeof(uint) ? OpCodes.Conv_Ovf_U4 - : type == typeof(long) ? OpCodes.Conv_Ovf_I8 - : type == typeof(ulong) ? OpCodes.Conv_Ovf_U8 - : type == typeof(IntPtr) ? OpCodes.Conv_Ovf_I - : type == typeof(UIntPtr) ? OpCodes.Conv_Ovf_U - : ThrowHelper.ThrowArgumentException($"Type {type.FullDescription()} cannot be converted to")); + return new(!type.IsPrimitive || type == typeof(char) + ? ThrowHelper.ThrowArgumentException( + "ConvertWithOverflowCheck expects a non-character primitive type") + : type == typeof(float) + ? ThrowHelper.ThrowInvalidOperationException( + "There is no operation for converting to a float with overflow checking") + : type == typeof(double) + ? ThrowHelper.ThrowInvalidOperationException( + "There is no operation for converting to a double with overflow checking") + : ConvertWithOverflowCheckOpCodesByType.TryGetValue(type, out var value) ? value + : ThrowHelper.ThrowArgumentException( + $"Type {type.FullDescription()} cannot be converted to")); } + public static readonly Dictionary ConvertWithOverflowCheckOpCodesByType = new() + { + { typeof(byte), OpCodes.Conv_Ovf_U1 }, + { typeof(sbyte), OpCodes.Conv_Ovf_I1 }, + { typeof(bool), OpCodes.Conv_Ovf_I1 }, + { typeof(short), OpCodes.Conv_Ovf_I2 }, + { typeof(ushort), OpCodes.Conv_Ovf_U2 }, + { typeof(int), OpCodes.Conv_Ovf_I4 }, + { typeof(uint), OpCodes.Conv_Ovf_U4 }, + { typeof(long), OpCodes.Conv_Ovf_I8 }, + { typeof(ulong), OpCodes.Conv_Ovf_U8 }, + { typeof(IntPtr), OpCodes.Conv_Ovf_I }, + { typeof(UIntPtr), OpCodes.Conv_Ovf_U } + }; + /// /// Converts the value on top of the evaluation stack to the given non-character primitive type /// as if it were unsigned, throwing System.OverflowException on overflow. @@ -1718,33 +2070,52 @@ public static class FishTranspiler { Guard.IsNotNull(type, nameof(type)); - return new( - !type.IsPrimitive || type == typeof(char) ? ThrowHelper.ThrowArgumentException("ConvertUnsignedWithOverflowCheck expects a non-character primitive type") - : type == typeof(float) ? ThrowHelper.ThrowInvalidOperationException("There is no operation for converting to a float with overflow checking") - : type == typeof(double) ? ThrowHelper.ThrowInvalidOperationException("There is no operation for converting to a double with overflow checking") - : type == typeof(byte) ? OpCodes.Conv_Ovf_U1_Un - : type == typeof(sbyte) ? OpCodes.Conv_Ovf_I1_Un - : type == typeof(short) ? OpCodes.Conv_Ovf_I2_Un - : type == typeof(ushort) ? OpCodes.Conv_Ovf_U2_Un - : type == typeof(int) ? OpCodes.Conv_Ovf_I4_Un - : type == typeof(uint) ? OpCodes.Conv_Ovf_U4_Un - : type == typeof(long) ? OpCodes.Conv_Ovf_I8_Un - : type == typeof(ulong) ? OpCodes.Conv_Ovf_U8_Un - : type == typeof(IntPtr) ? OpCodes.Conv_Ovf_I_Un - : type == typeof(UIntPtr) ? OpCodes.Conv_Ovf_U_Un - : ThrowHelper.ThrowArgumentException($"Type {type.FullDescription()} cannot be converted to")); + return new(!type.IsPrimitive || type == typeof(char) + ? ThrowHelper.ThrowArgumentException( + "ConvertUnsignedWithOverflowCheck expects a non-character primitive type") + : type == typeof(float) + ? ThrowHelper.ThrowInvalidOperationException( + "There is no operation for converting to a float with overflow checking") + : type == typeof(double) + ? ThrowHelper.ThrowInvalidOperationException( + "There is no operation for converting to a double with overflow checking") + : ConvertUnsignedWithOverflowCheckOpCodesByType.TryGetValue(type, out var value) ? value + : ThrowHelper.ThrowArgumentException( + $"Type {type.FullDescription()} cannot be converted to")); } - public static bool CallReturns(this CodeInstruction instruction, Type type) => (instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Call) && ((MethodInfo)instruction.operand).ReturnType == type; - public static bool FieldReturns(this CodeInstruction instruction, Type type) => (instruction.opcode == OpCodes.Ldfld || instruction.opcode == OpCodes.Ldsfld) && ((FieldInfo)instruction.operand).FieldType == type; - public static bool Returns(this CodeInstruction instruction, Type type) => instruction.CallReturns(type) || instruction.FieldReturns(type); + public static readonly Dictionary ConvertUnsignedWithOverflowCheckOpCodesByType = new() + { + { typeof(byte), OpCodes.Conv_Ovf_U1_Un }, + { typeof(sbyte), OpCodes.Conv_Ovf_I1_Un }, + { typeof(short), OpCodes.Conv_Ovf_I2_Un }, + { typeof(ushort), OpCodes.Conv_Ovf_U2_Un }, + { typeof(int), OpCodes.Conv_Ovf_I4_Un }, + { typeof(uint), OpCodes.Conv_Ovf_U4_Un }, + { typeof(long), OpCodes.Conv_Ovf_I8_Un }, + { typeof(ulong), OpCodes.Conv_Ovf_U8_Un }, + { typeof(IntPtr), OpCodes.Conv_Ovf_I_Un }, + { typeof(UIntPtr), OpCodes.Conv_Ovf_U_Un } + }; + + public static bool CallReturns(this CodeInstruction instruction, Type type) + => (instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Call) + && ((MethodInfo)instruction.operand).ReturnType == type; + + public static bool FieldReturns(this CodeInstruction instruction, Type type) + => (instruction.opcode == OpCodes.Ldfld || instruction.opcode == OpCodes.Ldsfld) + && ((FieldInfo)instruction.operand).FieldType == type; + + public static bool Returns(this CodeInstruction instruction, Type type) + => instruction.CallReturns(type) || instruction.FieldReturns(type); public static int FirstArgumentIndex(MethodBase method, Type argumentType) { Guard.IsNotNull(method); Guard.IsNotNull(argumentType); - return !method.IsStatic && method.DeclaringType == argumentType ? 0 + return !method.IsStatic && method.DeclaringType == argumentType + ? 0 : FirstArgumentIndex(method, p => p.ParameterType == argumentType); } @@ -1755,8 +2126,10 @@ public static class FishTranspiler var argument = method.GetParameters().FirstOrDefault(predicate); - return argument != null ? ArgumentIndex(argument) - : ThrowHelper.ThrowInvalidOperationException($"No argument found for predicate {predicate.Method.FullDescription()} and method {method.FullDescription()}"); + return argument != null + ? ArgumentIndex(argument) + : ThrowHelper.ThrowInvalidOperationException( + $"No argument found for predicate {predicate.Method.FullDescription()} and method {method.FullDescription()}"); } public static int ArgumentIndex(ParameterInfo parameter) @@ -1766,7 +2139,8 @@ public static class FishTranspiler return parameter.Position + (((MethodBase)parameter.Member).IsStatic ? 0 : 1); } - public static IEnumerable GetLocalOperandsOrIndices(CodeInstructions codes, Predicate predicate) + public static IEnumerable GetLocalOperandsOrIndices(CodeInstructions codes, + Predicate predicate) { Guard.IsNotNull(codes); Guard.IsNotNull(predicate); @@ -1778,8 +2152,10 @@ public static class FishTranspiler { yield return opcode.TryGetIndex() ?? TryGetIndexFromOperand(code.operand) - ?? ThrowHelper.ThrowNotSupportedException($"{code.opcode} returned {code.operand?.ToString() ?? "null"}."); + ?? ThrowHelper.ThrowNotSupportedException( + $"{code.opcode} returned {code.operand?.ToString() ?? "null"}."); } + previousCode = code; } } @@ -1798,7 +2174,11 @@ public static class FishTranspiler Guard.IsNotNull(method); Guard.IsNotNull(predicate); - var variables = method.GetMethodBody().LocalVariables; + var methodBody = method.GetMethodBody(); + if (methodBody is null) + ThrowHelper.ThrowArgumentException($"Method {method.FullDescription()} has no body"); + + var variables = methodBody.LocalVariables; for (var i = 0; i < variables.Count; i++) { if (predicate(variables[i])) @@ -1806,7 +2186,8 @@ public static class FishTranspiler } } - public static CodeInstructions MethodReplacer(this CodeInstructions instructions, T from, V to, bool throwOnFailure = true) where T : Delegate where V : Delegate + public static CodeInstructions MethodReplacer(this CodeInstructions instructions, T from, V to, + bool throwOnFailure = true) where T : Delegate where V : Delegate { Guard.IsNotNull(instructions); Guard.IsNotNull(from); @@ -1815,20 +2196,27 @@ public static class FishTranspiler var success = false; foreach (var instruction in instructions) { - if ((instruction.operand as MethodBase) == from.Method) + if (instruction.operand as MethodBase == from.Method) { instruction.opcode = to.Method.IsStatic ? OpCodes.Call : OpCodes.Callvirt; instruction.operand = to.Method; success = true; } + yield return instruction; } if (throwOnFailure && !success) - UtilityF.Throw($"FishTranspiler.MethodReplacer couldn't find method {to.Method.FullDescription()} for {UtilityF.GetCallingAssembly().GetName().Name}, Version {UtilityF.GetCallingAssembly().GetName().Version}"); + { + ThrowHelper.ThrowInvalidOperationException( + $"FishTranspiler.MethodReplacer couldn't find method {to.Method.FullDescription()} for { + UtilityF.GetCallingAssembly().GetName().Name}, Version { + UtilityF.GetCallingAssembly().GetName().Version}"); + } } - public static CodeInstructions InsertBefore(this CodeInstructions instructions, Predicate predicate, CodeInstruction instructionToInsert, bool throwOnFailure = true) + public static CodeInstructions InsertBefore(this CodeInstructions instructions, + Predicate predicate, CodeInstruction instructionToInsert, bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(predicate); @@ -1837,7 +2225,8 @@ public static class FishTranspiler return instructions.InsertBefore(predicate, new[] { instructionToInsert }, throwOnFailure); } - public static CodeInstructions InsertBefore(this CodeInstructions instructions, Predicate predicate, CodeInstructions instructionsToInsert, bool throwOnFailure = true) + public static CodeInstructions InsertBefore(this CodeInstructions instructions, + Predicate predicate, CodeInstructions instructionsToInsert, bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(predicate); @@ -1850,16 +2239,24 @@ public static class FishTranspiler { foreach (var instruction in instructionsToInsert) yield return instruction; + success = true; } + yield return code; } if (throwOnFailure && !success) - UtilityF.Throw($"FishTranspiler.InsertBefore couldn't find target instruction for {predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {UtilityF.GetCallingAssembly().GetName().Version}"); + { + ThrowHelper.ThrowInvalidOperationException( + $"FishTranspiler.InsertBefore couldn't find target instruction for { + predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version { + UtilityF.GetCallingAssembly().GetName().Version}"); + } } - public static CodeInstructions InsertAfter(this CodeInstructions instructions, Predicate predicate, CodeInstruction instructionToInsert, bool throwOnFailure = true) + public static CodeInstructions InsertAfter(this CodeInstructions instructions, Predicate predicate, + CodeInstruction instructionToInsert, bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(predicate); @@ -1868,7 +2265,8 @@ public static class FishTranspiler return instructions.InsertAfter(predicate, new[] { instructionToInsert }, throwOnFailure); } - public static CodeInstructions InsertAfter(this CodeInstructions instructions, Predicate predicate, CodeInstructions instructionsToInsert, bool throwOnFailure = true) + public static CodeInstructions InsertAfter(this CodeInstructions instructions, Predicate predicate, + CodeInstructions instructionsToInsert, bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(predicate); @@ -1878,19 +2276,27 @@ public static class FishTranspiler foreach (var code in instructions) { yield return code; - if (predicate(code)) - { - foreach (var instruction in instructionsToInsert) - yield return instruction; - success = true; - } + + if (!predicate(code)) + continue; + + foreach (var instruction in instructionsToInsert) + yield return instruction; + + success = true; } if (throwOnFailure && !success) - UtilityF.Throw($"FishTranspiler.InsertAfter couldn't find target instruction for {predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {UtilityF.GetCallingAssembly().GetName().Version}"); + { + ThrowHelper.ThrowInvalidOperationException( + $"FishTranspiler.InsertAfter couldn't find target instruction for { + predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version { + UtilityF.GetCallingAssembly().GetName().Version}"); + } } - public static CodeInstructions Replace(this CodeInstructions instructions, Predicate predicate, Func replacement, bool throwOnFailure = true) + public static CodeInstructions Replace(this CodeInstructions instructions, Predicate predicate, + Func replacement, bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(predicate); @@ -1899,7 +2305,8 @@ public static class FishTranspiler return instructions.Replace(predicate, c => new[] { replacement(c) }, throwOnFailure); } - public static CodeInstructions Replace(this CodeInstructions instructions, Predicate predicate, Func replacement, bool throwOnFailure = true) + public static CodeInstructions Replace(this CodeInstructions instructions, Predicate predicate, + Func replacement, bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(predicate); @@ -1912,19 +2319,25 @@ public static class FishTranspiler { foreach (var instruction in replacement(code)) yield return instruction; + success = true; } else - { yield return code; - } } if (throwOnFailure && !success) - UtilityF.Throw($"FishTranspiler.Replace couldn't find target instruction for {predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {UtilityF.GetCallingAssembly().GetName().Version}"); + { + ThrowHelper.ThrowInvalidOperationException( + $"FishTranspiler.Replace couldn't find target instruction for { + predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version { + UtilityF.GetCallingAssembly().GetName().Version}"); + } } - public static CodeInstructions ReplaceAt(this CodeInstructions instructions, Func, int, bool> position, Func replacement, bool throwOnFailure = true) + public static CodeInstructions ReplaceAt(this CodeInstructions instructions, + Func, int, bool> position, Func replacement, + bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(position); @@ -1933,7 +2346,9 @@ public static class FishTranspiler return instructions.ReplaceAt(position, c => new[] { replacement(c) }, throwOnFailure); } - public static CodeInstructions ReplaceAt(this CodeInstructions instructions, Func, int, bool> position, Func replacement, bool throwOnFailure = true) + public static CodeInstructions ReplaceAt(this CodeInstructions instructions, + Func, int, bool> position, Func replacement, + bool throwOnFailure = true) { Guard.IsNotNull(instructions); Guard.IsNotNull(position); @@ -1943,28 +2358,31 @@ public static class FishTranspiler var codes = instructions as List ?? instructions.ToList(); for (var i = 0; i < codes.Count; i++) { - if (position(codes, i)) - { - var code = codes[i]; - codes.RemoveAt(i); + if (!position(codes, i)) + continue; - var replacementList = replacement(code).ToList(); - codes.InsertRange(i, replacementList); - i += replacementList.Count - 1; - success = true; - } + var code = codes[i]; + codes.RemoveAt(i); + + var replacementList = replacement(code).ToList(); + codes.InsertRange(i, replacementList); + i += replacementList.Count - 1; + success = true; } if (throwOnFailure && !success) { - UtilityF.Throw( - $"FishTranspiler.ReplaceAt couldn't find target instruction for {position.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {UtilityF.GetCallingAssembly().GetName().Version}"); + ThrowHelper.ThrowInvalidOperationException( + $"FishTranspiler.ReplaceAt couldn't find target instruction for { + position.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version { + UtilityF.GetCallingAssembly().GetName().Version}"); } return codes; } - public static CodeInstruction With(this CodeInstruction instruction, OpCode? opcode = null, object? operand = null, IEnumerable