From 59ea7c447a8ea82c578b543b733107d0491c92e2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 05:01:03 +0000 Subject: [PATCH 1/2] perf: HtmlCharRefs entity lookup uses Dictionary for O(1) instead of Map O(log n) Replace the F# Map (O(log n) per lookup) with a Dictionary (O(1) per lookup) for the ~2230 HTML named-entity table. Also introduce a static semiColonChars array to avoid allocating a new char[] on every call to TrimEnd inside the (|Number|Lookup|) active pattern. Bump version to 8.1.10. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- RELEASE_NOTES.md | 4 ++++ src/AssemblyInfo.Csv.Core.fs | 8 ++++---- src/AssemblyInfo.DesignTime.fs | 8 ++++---- src/AssemblyInfo.Html.Core.fs | 8 ++++---- src/AssemblyInfo.Http.fs | 8 ++++---- src/AssemblyInfo.Json.Core.fs | 8 ++++---- src/AssemblyInfo.Runtime.Utilities.fs | 8 ++++---- src/AssemblyInfo.WorldBank.Core.fs | 8 ++++---- src/AssemblyInfo.Xml.Core.fs | 8 ++++---- src/AssemblyInfo.fs | 8 ++++---- src/FSharp.Data.Html.Core/HtmlCharRefs.fs | 23 +++++++++++++++++++---- 11 files changed, 59 insertions(+), 40 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7f0e63a1c..08aa6011b 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,9 @@ # Release Notes +## 8.1.10 - Apr 20 2026 + +- Performance: `HtmlCharRefs` entity lookup now uses a `Dictionary` instead of an F# `Map`, giving O(1) lookups instead of O(log n) for ~2230 HTML named-entity entries. Also avoids a repeated `char[]` allocation in the `TrimEnd` call inside the active pattern. + ## 8.1.9 - Apr 18 2026 - Fix: `Caching.hashString` now disposes the `SHA1` instance after use; on .NET 5+ uses `SHA1.HashData` (static, pool-backed) to avoid allocation entirely (PR #1745) diff --git a/src/AssemblyInfo.Csv.Core.fs b/src/AssemblyInfo.Csv.Core.fs index 5623231ac..ca9103f98 100644 --- a/src/AssemblyInfo.Csv.Core.fs +++ b/src/AssemblyInfo.Csv.Core.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.Csv.Core" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.DesignTime.fs b/src/AssemblyInfo.DesignTime.fs index b67ba1cac..beeda0a2c 100644 --- a/src/AssemblyInfo.DesignTime.fs +++ b/src/AssemblyInfo.DesignTime.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.DesignTime" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.Html.Core.fs b/src/AssemblyInfo.Html.Core.fs index e5b93c216..b5b1b62cd 100644 --- a/src/AssemblyInfo.Html.Core.fs +++ b/src/AssemblyInfo.Html.Core.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.Html.Core" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.Http.fs b/src/AssemblyInfo.Http.fs index e51991195..38b8b070a 100644 --- a/src/AssemblyInfo.Http.fs +++ b/src/AssemblyInfo.Http.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.Http" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.Json.Core.fs b/src/AssemblyInfo.Json.Core.fs index 9d5a31d53..73cb24591 100644 --- a/src/AssemblyInfo.Json.Core.fs +++ b/src/AssemblyInfo.Json.Core.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.Json.Core" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.Runtime.Utilities.fs b/src/AssemblyInfo.Runtime.Utilities.fs index fe43116ae..f2480a7bb 100644 --- a/src/AssemblyInfo.Runtime.Utilities.fs +++ b/src/AssemblyInfo.Runtime.Utilities.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.Runtime.Utilities" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.WorldBank.Core.fs b/src/AssemblyInfo.WorldBank.Core.fs index 8aa17f401..70814c3be 100644 --- a/src/AssemblyInfo.WorldBank.Core.fs +++ b/src/AssemblyInfo.WorldBank.Core.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.WorldBank.Core" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.Xml.Core.fs b/src/AssemblyInfo.Xml.Core.fs index 385334d0d..e235dabf3 100644 --- a/src/AssemblyInfo.Xml.Core.fs +++ b/src/AssemblyInfo.Xml.Core.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data.Xml.Core" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/AssemblyInfo.fs b/src/AssemblyInfo.fs index ee5f12b23..88b5d75a0 100644 --- a/src/AssemblyInfo.fs +++ b/src/AssemblyInfo.fs @@ -5,13 +5,13 @@ open System.Reflection [] [] [] -[] -[] +[] +[] do () module internal AssemblyVersionInformation = let [] AssemblyTitle = "FSharp.Data" let [] AssemblyProduct = "FSharp.Data" let [] AssemblyDescription = "Library of F# type providers and data access tools" - let [] AssemblyVersion = "8.1.9.0" - let [] AssemblyFileVersion = "8.1.9.0" + let [] AssemblyVersion = "8.1.10.0" + let [] AssemblyFileVersion = "8.1.10.0" diff --git a/src/FSharp.Data.Html.Core/HtmlCharRefs.fs b/src/FSharp.Data.Html.Core/HtmlCharRefs.fs index bb9f6f9a3..c0d85a26c 100644 --- a/src/FSharp.Data.Html.Core/HtmlCharRefs.fs +++ b/src/FSharp.Data.Html.Core/HtmlCharRefs.fs @@ -1,11 +1,16 @@ namespace FSharp.Data open System +open System.Collections.Generic open System.Globalization module internal HtmlCharRefs = - let private refs = + // Avoid a new char[] allocation on every TrimEnd call + let private semiColonChars = [| ';' |] + + // ~2230 HTML named-entity entries; stored as a Dictionary for O(1) lookup + let private refsEntries = [| "Á", "\u00C1" "Á", "\u00C1" "á", "\u00E1" @@ -2237,10 +2242,17 @@ module internal HtmlCharRefs = "𝓏", "\uD835\uDCCF" "‍", "\u200D" "‌", "\u200C" |] - |> Map.ofArray + + let private refs = + let d = Dictionary(refsEntries.Length, StringComparer.Ordinal) + + for k, v in refsEntries do + d.[k] <- v + + d let (|Number|Lookup|) (orig: string) = - let s = orig.TrimEnd([| ';' |]) + let s = orig.TrimEnd(semiColonChars) if s.Length > 2 then let (delimeters, discriminator) = @@ -2275,4 +2287,7 @@ module internal HtmlCharRefs = string lead + string tail else string (char num) - | Lookup(ref) -> defaultArg (refs.TryFind ref) ref + | Lookup(ref) -> + match refs.TryGetValue(ref) with + | true, v -> v + | false, _ -> ref From 1c2912ce15e17ee4dfb8f5e42b1bd7f0e97a5f87 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 20 Apr 2026 05:01:06 +0000 Subject: [PATCH 2/2] ci: trigger checks