From af6af47efafb253833dad34c70028b0401c101de Mon Sep 17 00:00:00 2001 From: aka-nse Date: Tue, 17 Feb 2026 23:41:06 +0900 Subject: [PATCH 1/7] adds link --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c18cac7..caeda52 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ Code path performance monitoring tool. +[](https://github.com/aka-nse/PathBench/) + +[](https://www.nuget.org/packages/akanse.PathBench/) + ---- ## Features From 13547c12024f2368e570d709addaab138ac133ff Mon Sep 17 00:00:00 2001 From: aka-nse Date: Tue, 17 Feb 2026 23:44:29 +0900 Subject: [PATCH 2/7] includes resource into package --- src/PathBench/PathBench.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PathBench/PathBench.csproj b/src/PathBench/PathBench.csproj index d33b87c..004c05a 100644 --- a/src/PathBench/PathBench.csproj +++ b/src/PathBench/PathBench.csproj @@ -21,6 +21,7 @@ + From 295308ac990157bee17b98f86d40b462ad5d7837 Mon Sep 17 00:00:00 2001 From: Daishi Nakase Date: Sat, 28 Feb 2026 22:00:42 +0900 Subject: [PATCH 3/7] adds copilot instructions --- .github/copilot-instructions.md | 65 +++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..a38b718 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,65 @@ +# Copilot Instructions for PathBench + +## What's this file for? + +- This file provides instructions for generating source or operating as an agent + for this repository to GitHub Copilot or other AI code assistants. +- When implementing new features, please use the technology selection, + design policy, and module configuration shown here as a premise. +- If in doubt, explore the files in the repository and ask the user "Is this + what you meant?" + +## Preconditions + +- The comments or documentations in the source codes must be in English unless + there is specific instructions. +- The answer in the shell writes in user local language as possible as. +- When making code changes, if the number of lines modified is likely to exceed + 200, please prompt the user beforehand with the message: "This instruction may + result in over 200 lines of code being modified. Do you wish to proceed?" +- When making significant changes, first create a plan outlining what you intend + to do, then propose it to the user by saying, "We plan to proceed with this + approach." If the user requests modifications to the plan at this stage, + revise the plan accordingly and resubmit it. + +## Project overview + +PathBench is a .NET library for benchmarking and analyzing the performance of +different algorithms and data structures. It provides a way to measure execution +time, allowing developers to optimize their code effectively. + +Please refer to the [README.md](../README.md) for more details about the +project, including its features, installation instructions, and usage examples. + +## Directories and files + +This project has the following directory structure: + +``` +./ ++-- .editorconfig # Editor configuration file ++-- .gitignore # Git ignore file ++-- Directory.Build.props # MSBuild shared properties for the project ++-- LICENSE.txt # License information for the project ++-- Measure-Coverage.ps1 # PowerShell script for measuring code coverage ++-- PathBench.slnx # Visual Studio solution file ++-- README.md # Project overview and documentation ++-- global.json # .NET SDK version configuration ++-- .github/ +| +-- workflows/ # GitHub Actions workflow files +| | +-- dotnet-CI.yml # CI workflow for .NET builds and tests +| +-- copilot-instructions.md # This file: instructions for GitHub Copilot ++-- resources/ # Misc. resource files for the project ++-- src/ # Source code for the library +| +-- PathBench/ # Main library code ++ tests/ # Unit tests for the library + +-- PathBench.Test/ # Unit tests for the library + +-- etc/ + +-- coverlet.runsettings # Coverlet configuration for code coverage analysis +``` + +## Coding style + +- Unless specific commented, the coding style should follow .editorconfig file. +- Unless specific commented, the coding style should follow the [Microsoft C# coding conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions). +- All of public members must have XML documentation comments. From b9cd504843b6b305201bdb87b1574ba561397189 Mon Sep 17 00:00:00 2001 From: Daishi Nakase Date: Wed, 17 Jun 2026 00:50:30 +0900 Subject: [PATCH 4/7] supports netstandard2.0 --- .../MethodProfileReportFormatter.Graphviz.cs | 16 +-- src/PathBench/PathBench.csproj | 11 +- src/PathBench/PreciseDuration.cs | 14 ++- src/PathBench/__FrameworkCompatibility.cs | 111 ++++++++++++++++++ 4 files changed, 141 insertions(+), 11 deletions(-) create mode 100644 src/PathBench/__FrameworkCompatibility.cs 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 From d593ea93655206f92c6ff76ac76e9c22fac34d28 Mon Sep 17 00:00:00 2001 From: Daishi Nakase Date: Wed, 17 Jun 2026 00:50:41 +0900 Subject: [PATCH 5/7] adds test for net8.0 --- ...thodProfileReportFormatter.GraphvizTest.cs | 26 +++++++++++++++++++ tests/PathBench.Test/PathBench.Test.csproj | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) 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 From 3db43cfd04aa7974d571e4325acfb0e9e5d4072e Mon Sep 17 00:00:00 2001 From: Daishi Nakase Date: Wed, 17 Jun 2026 00:55:21 +0900 Subject: [PATCH 6/7] increments version number --- src/PathBench/PathBench.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PathBench/PathBench.csproj b/src/PathBench/PathBench.csproj index ada4ef4..d2eecea 100644 --- a/src/PathBench/PathBench.csproj +++ b/src/PathBench/PathBench.csproj @@ -10,7 +10,7 @@ akanse.$(AssemblyName) PathBench - 1.0.0 + 1.1.0 PathBench Code path performance monitoring tool. From 79c1d0e91fed8c16060dfa069085382dd29159c1 Mon Sep 17 00:00:00 2001 From: Daishi Nakase Date: Wed, 17 Jun 2026 00:56:27 +0900 Subject: [PATCH 7/7] updates readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index caeda52..093521f 100644 --- a/README.md +++ b/README.md @@ -99,3 +99,7 @@ static class SampleClass ### v1.0.0 - First release + +### v1.1.0 + +- Adds support for net standard 2.0