diff --git a/src/PathBench/MethodProfileReportFormatter.Graphviz.cs b/src/PathBench/MethodProfileReportFormatter.Graphviz.cs
index 1962dcc..3d72fb3 100644
--- a/src/PathBench/MethodProfileReportFormatter.Graphviz.cs
+++ b/src/PathBench/MethodProfileReportFormatter.Graphviz.cs
@@ -86,17 +86,17 @@ public static string SanitizeIdentifier(string name)
{
var sb = new StringBuilder();
sb.Append("__");
- foreach (var c in name.EnumerateRunes())
+ foreach (var c in name)
{
- switch (c.Value)
+ switch (c)
{
- case >= 0x30 and < 0x3A:
- case >= 0x41 and < 0x5B:
- case >= 0x61 and < 0x7B:
+ case >= (char)0x30 and < (char)0x3A:
+ case >= (char)0x41 and < (char)0x5B:
+ case >= (char)0x61 and < (char)0x7B:
sb.Append(c);
continue;
default:
- sb.Append($"_u{(uint)c.Value:X04}_");
+ sb.Append($"_u{(uint)c:X04}_");
continue;
}
}
@@ -106,9 +106,9 @@ public static string SanitizeIdentifier(string name)
public static string SanitizeLabel(string name)
{
var sb = new StringBuilder(name.Length * 2);
- foreach (var c in name.EnumerateRunes())
+ foreach (var c in name)
{
- switch (c.Value)
+ switch (c)
{
case '\n':
sb.Append(@"\n");
diff --git a/src/PathBench/PathBench.csproj b/src/PathBench/PathBench.csproj
index 004c05a..ada4ef4 100644
--- a/src/PathBench/PathBench.csproj
+++ b/src/PathBench/PathBench.csproj
@@ -1,7 +1,8 @@
- net10.0
+
+ net10.0;netstandard2.0
True
@@ -25,4 +26,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/PathBench/PreciseDuration.cs b/src/PathBench/PreciseDuration.cs
index 135be56..c344e32 100644
--- a/src/PathBench/PreciseDuration.cs
+++ b/src/PathBench/PreciseDuration.cs
@@ -1,4 +1,6 @@
+#if NET7_0_OR_GREATER
using System.Numerics;
+#endif
using System.Text.RegularExpressions;
namespace PathBench;
@@ -9,9 +11,11 @@ namespace PathBench;
public readonly partial struct PreciseDuration(long ticks)
: IEquatable
, IComparable
+#if NET7_0_OR_GREATER
, IComparisonOperators
, IAdditionOperators
, ISubtractionOperators
+#endif
, IFormattable
{
///
@@ -202,8 +206,14 @@ public static PreciseDuration FromNanoseconds(double nanoseconds) =>
#region ToString overloads
- [GeneratedRegex(@"^(?.+?)(?nsec|usec|msec|sec|)$")]
+ //lang=regex
+ private const string _formatMatchingPattern = @"^(?.+?)(?nsec|usec|msec|sec|)$";
+#if NET7_0_OR_GREATER
+ [GeneratedRegex(_formatMatchingPattern)]
private static partial Regex GetFormatMatcher();
+#else
+ private static Regex GetFormatMatcher() => new (_formatMatchingPattern, RegexOptions.Compiled);
+#endif
private static readonly Regex _FormatMatcher = GetFormatMatcher();
///
@@ -279,7 +289,7 @@ public string ToString(string? realPartFormat, TimeScale timeScale, IFormatProvi
_ => throw new FormatException("Invalid time scale."),
};
- #endregion ToString overloads
+#endregion ToString overloads
///
[ExcludeFromCodeCoverage]
diff --git a/src/PathBench/__FrameworkCompatibility.cs b/src/PathBench/__FrameworkCompatibility.cs
new file mode 100644
index 0000000..5283430
--- /dev/null
+++ b/src/PathBench/__FrameworkCompatibility.cs
@@ -0,0 +1,111 @@
+#pragma warning disable IDE0079 // Remove unnecessary suppression
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+
+#if !NET5_0_OR_GREATER
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.CompilerServices
+{
+ internal static class IsExternalInit;
+}
+
+namespace System.Runtime.InteropServices
+{
+ internal static class CollectionsMarshal
+ {
+ private sealed class ListCompat
+ {
+ internal T[]? _items = default; // Do not rename (binary serialization)
+ internal int _size = default; // Do not rename (binary serialization)
+ internal int _version = default; // Do not rename (binary serialization)
+ }
+
+ public static ReadOnlySpan AsSpan(List? list)
+ {
+ Span span = default;
+ if (list is not null)
+ {
+ var listCompat = Unsafe.As, ListCompat>(ref list);
+ int size = listCompat._size;
+ T[] items = listCompat._items!;
+
+ if ((uint)size > (uint)items.Length)
+ {
+ throw new InvalidOperationException();
+ }
+
+ span = items.AsSpan(0, size);
+ }
+
+ return span;
+ }
+ }
+}
+#endif
+
+#if !NET7_0_OR_GREATER
+namespace System
+{
+ internal static class TimeSpanExtensions
+ {
+ extension(TimeSpan ts)
+ {
+ public static long TicksPerMicrosecond => TimeSpan.TicksPerMillisecond / 1000;
+ }
+ }
+}
+#endif
+
+#if !NET9_0_OR_GREATER
+namespace System.Threading
+{
+ internal class Lock
+ {
+ private sealed class Scope(object token) : IDisposable
+ {
+ public void Dispose()
+ {
+ Monitor.Exit(token);
+ }
+ }
+
+ private readonly object _token = new();
+
+ internal IDisposable EnterScope()
+ {
+ Monitor.Enter(_token);
+ return new Scope(_token);
+ }
+ }
+}
+#endif
+
+#if !NETSTANDARD2_1_OR_GREATER && !NETCOREAPP2_0_OR_GREATER
+namespace System.Collections.Generic
+{
+ internal static class CollectionExtensions
+ {
+ extension(IDictionary dict)
+ {
+ public bool TryAdd(TKey key, TValue value)
+ {
+ if (dict.ContainsKey(key)) return false;
+ dict.Add(key, value);
+ return true;
+ }
+ }
+
+ extension(KeyValuePair kv)
+ {
+ public void Deconstruct(out TKey key, out TValue value)
+ {
+ key = kv.Key;
+ value = kv.Value;
+ }
+ }
+ }
+}
+#endif
+
+#pragma warning restore IDE0130 // Namespace does not match folder structure
+#pragma warning restore IDE0079 // Remove unnecessary suppression
\ No newline at end of file
diff --git a/tests/PathBench.Test/MethodProfileReportFormatter.GraphvizTest.cs b/tests/PathBench.Test/MethodProfileReportFormatter.GraphvizTest.cs
index 3a461ff..dabba76 100644
--- a/tests/PathBench.Test/MethodProfileReportFormatter.GraphvizTest.cs
+++ b/tests/PathBench.Test/MethodProfileReportFormatter.GraphvizTest.cs
@@ -1,3 +1,4 @@
+using System.Reflection;
using System.Runtime.CompilerServices;
namespace PathBench.Test;
@@ -9,6 +10,8 @@ private static class PrivateAccess
public const string _typeName =
$"{nameof(PathBench)}.{nameof(MethodProfileReportFormatter)}+GraphvizStyle_, PathBench";
+#if NET10_0_OR_GREATER
+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SanitizeIdentifier")]
public extern static string SanitizeIdentifier(
[UnsafeAccessorType(_typeName)] object? _,
@@ -18,6 +21,29 @@ public extern static string SanitizeIdentifier(
public extern static string SanitizeLabel(
[UnsafeAccessorType(_typeName)] object? _,
string input);
+
+#else
+ private static readonly Type _GraphvizStyle_ =
+ typeof(MethodProfileReportFormatter)
+ .GetNestedType("GraphvizStyle_", BindingFlags.NonPublic)!;
+
+ private static readonly MethodInfo _SanitizeIdentifier =
+ _GraphvizStyle_.GetMethod("SanitizeIdentifier", BindingFlags.Public | BindingFlags.Static)!;
+
+ private static readonly MethodInfo _SanitizeLabel =
+ _GraphvizStyle_.GetMethod("SanitizeLabel", BindingFlags.Public | BindingFlags.Static)!;
+
+ public static string SanitizeIdentifier(object? _, string input)
+ {
+ return (string)_SanitizeIdentifier.Invoke(null, [input])!;
+ }
+
+ public static string SanitizeLabel(object? _, string input)
+ {
+ return (string)_SanitizeLabel.Invoke(null, [input])!;
+ }
+
+#endif
}
public static TheoryData SanitizeIdentifierTestCases() =>
diff --git a/tests/PathBench.Test/PathBench.Test.csproj b/tests/PathBench.Test/PathBench.Test.csproj
index 4abab7a..e3530fb 100644
--- a/tests/PathBench.Test/PathBench.Test.csproj
+++ b/tests/PathBench.Test/PathBench.Test.csproj
@@ -1,7 +1,7 @@
- net10.0
+ net8.0;net10.0
enable
enable
false