From 1133cf4c77734567a3ce7e5d9e90d9bcf1e9812b Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Sun, 2 Aug 2026 02:20:03 +0100 Subject: [PATCH] perf(SourceLength): String.Concat -> StringBuilder Having another look at this, doing multiple remove operations on a StringBuilders looks to be more efficient than multiple String.Concat calls, even when using Spans Benchmark before: ``` | Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated | |--------------- |--------:|---------:|---------:|-----------:|----------:|----------:|----------:| | LintParsedFile | 1.299 s | 0.0113 s | 0.0100 s | 15000.0000 | 6000.0000 | 2000.0000 | 262.67 MB | ``` After: ``` | Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated | |--------------- |--------:|---------:|---------:|-----------:|----------:|----------:|----------:| | LintParsedFile | 1.264 s | 0.0114 s | 0.0101 s | 14000.0000 | 5000.0000 | 1000.0000 | 233.47 MB | ``` --- .../SourceLength/SourceLengthHelper.fs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs index d2735ec43..965233303 100644 --- a/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs +++ b/src/FSharpLint.Core/Rules/Conventions/SourceLength/SourceLengthHelper.fs @@ -1,6 +1,7 @@ module FSharpLint.Rules.Helper.SourceLength open System +open System.Text open System.Text.RegularExpressions open FSharpLint.Framework open FSharpLint.Framework.Suggestion @@ -51,13 +52,15 @@ let checkSourceLengthRule (config:Config) range fileContents errorName (skipRang |> Seq.sortBy (function | Begin index -> index | End index -> index) |> Seq.toList - getTopLevelBalancedPairs markers List.Empty - |> List.fold - (fun (currSource: string) (startIndex, endIndex) -> - let left = currSource.AsSpan(0, startIndex) - let right = currSource.AsSpan(endIndex + multilineCommentMarkerRegexCaptureGroupLength) - String.Concat(left, right)) - source + match getTopLevelBalancedPairs markers List.Empty with + | [] -> source + | pairs -> + + (StringBuilder(source), pairs) + ||> List.fold + (fun (currSource: StringBuilder) (startIndex, endIndex) -> + currSource.Remove(startIndex, (endIndex + multilineCommentMarkerRegexCaptureGroupLength) - startIndex)) + |> _.ToString() match tryFindTextOfRange range fileContents with | Some(sourceCode) ->