From 6b2b99be1239c3fc1e20c067a1efaaf47b41ca9a Mon Sep 17 00:00:00 2001 From: rboy1 <3846367+rboy1@users.noreply.github.com> Date: Wed, 1 Oct 2025 18:47:02 -0400 Subject: [PATCH 1/4] Improve performance ~20% performance improvement, significant improvement when parsing large INI files --- Src/ConfigurationReader.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Src/ConfigurationReader.cs b/Src/ConfigurationReader.cs index 369b207..3e217c3 100644 --- a/Src/ConfigurationReader.cs +++ b/Src/ConfigurationReader.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Text; +using System.Collections.Generic; namespace SharpConfig { @@ -122,11 +123,14 @@ private static string ParseComment(string line, out int commentCharIndex) int index = 0; int quoteCount = 0; - while (line.Length > index) // traverse line from left to right + int length = line.Length; + HashSet validCommentChars = new HashSet(Configuration.ValidCommentChars); // Use HashSet for O(1) lookup instead of Array.IndexOf for O(n) + while (index < length) // traverse line from left to right { - bool isValidCommentChar = Array.IndexOf(Configuration.ValidCommentChars, line[index]) > -1; - bool isQuotationMark = line[index] == '\"'; - bool isCharWithinQuotes = quoteCount % 2 == 1; + char currentChar = line[index]; + bool isValidCommentChar = validCommentChars.Contains(currentChar); + bool isQuotationMark = currentChar == '\"'; + bool isCharWithinQuotes = (quoteCount & 1) == 1; // bitwise AND is slightly faster bool isCharEscaped = index > 0 && line[index - 1] == '\\'; if (isValidCommentChar && !isCharWithinQuotes && !isCharEscaped) From f60e371c67534c23b02556889716cbf082a5f9e6 Mon Sep 17 00:00:00 2001 From: rboy1 <3846367+rboy1@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:30:55 -0400 Subject: [PATCH 2/4] Optimize performance Creating HashSet is expensive when reading large file, since the validCommentChars do not change over the course of a single read API, initialize it once and use to to read entire file. Improves performance by about 15% --- Src/ConfigurationReader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Src/ConfigurationReader.cs b/Src/ConfigurationReader.cs index 3e217c3..81a87e1 100644 --- a/Src/ConfigurationReader.cs +++ b/Src/ConfigurationReader.cs @@ -26,6 +26,7 @@ private static void Parse(StringReader reader, Configuration config) { var currentSection = new Section(Section.DefaultSectionName); var preCommentBuilder = new StringBuilder(); + HashSet validCommentChars = new HashSet(Configuration.ValidCommentChars); // Initialize once for ecah file to optimize performance int lineNumber = 0; @@ -45,7 +46,7 @@ private static void Parse(StringReader reader, Configuration config) continue; } - var comment = ParseComment(line, out int commentIndex); + var comment = ParseComment(line, validCommentChars, out int commentIndex); if (commentIndex == 0) { @@ -109,7 +110,7 @@ private static void Parse(StringReader reader, Configuration config) } } - private static string ParseComment(string line, out int commentCharIndex) + private static string ParseComment(string line, HashSet validCommentChars, out int commentCharIndex) { // A comment starts with a valid comment character that: // 1. is not within a quote (eg. "this is # not a comment"), and @@ -124,7 +125,6 @@ private static string ParseComment(string line, out int commentCharIndex) int index = 0; int quoteCount = 0; int length = line.Length; - HashSet validCommentChars = new HashSet(Configuration.ValidCommentChars); // Use HashSet for O(1) lookup instead of Array.IndexOf for O(n) while (index < length) // traverse line from left to right { char currentChar = line[index]; From fb9f4e352a0c0433e760096304ef6527ff9b90f9 Mon Sep 17 00:00:00 2001 From: rboy1 <3846367+rboy1@users.noreply.github.com> Date: Thu, 2 Oct 2025 13:56:57 -0400 Subject: [PATCH 3/4] typos in comments --- Src/ConfigurationReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/ConfigurationReader.cs b/Src/ConfigurationReader.cs index 81a87e1..b5b2647 100644 --- a/Src/ConfigurationReader.cs +++ b/Src/ConfigurationReader.cs @@ -26,7 +26,7 @@ private static void Parse(StringReader reader, Configuration config) { var currentSection = new Section(Section.DefaultSectionName); var preCommentBuilder = new StringBuilder(); - HashSet validCommentChars = new HashSet(Configuration.ValidCommentChars); // Initialize once for ecah file to optimize performance + HashSet validCommentChars = new HashSet(Configuration.ValidCommentChars); // Initialize once for each reader to optimize performance int lineNumber = 0; From ca5db3aabcf3ca637a593325404eec6cd9e73478 Mon Sep 17 00:00:00 2001 From: Cem Dervis Date: Sat, 25 Oct 2025 15:57:52 +0200 Subject: [PATCH 4/4] Change ValidCommentChars to HashSet --- Src/Configuration.cs | 6 +++--- Src/ConfigurationReader.cs | 8 +++----- Src/Setting.cs | 5 ++++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Src/Configuration.cs b/Src/Configuration.cs index 4c0960f..27caf4f 100644 --- a/Src/Configuration.cs +++ b/Src/Configuration.cs @@ -35,7 +35,7 @@ static Configuration() // but without modifying the real invariant culture instance. s_cultureInfo = (CultureInfo)CultureInfo.InvariantCulture.Clone(); - ValidCommentChars = new[] { '#', ';' }; + ValidCommentChars = new HashSet { '#', ';' }; s_preferredCommentChar = '#'; s_arrayElementSeparator = ','; @@ -585,7 +585,7 @@ public static CultureInfo CultureInfo /// Gets the array that contains all valid comment delimiting characters. /// The current value is { '#', ';' }. /// - public static char[] ValidCommentChars { get; private set; } + public static HashSet ValidCommentChars { get; private set; } /// /// Gets or sets the preferred comment char when saving configurations. @@ -597,7 +597,7 @@ public static char PreferredCommentChar { get => s_preferredCommentChar; set { - if (!Array.Exists(ValidCommentChars, c => c == value)) + if (!ValidCommentChars.Contains(value)) { throw new ArgumentException("The specified char '" + value + "' is not allowed as a comment char."); } diff --git a/Src/ConfigurationReader.cs b/Src/ConfigurationReader.cs index b170452..d6c430b 100644 --- a/Src/ConfigurationReader.cs +++ b/Src/ConfigurationReader.cs @@ -4,7 +4,6 @@ using System; using System.IO; using System.Text; -using System.Collections.Generic; namespace SharpConfig { @@ -26,7 +25,6 @@ private static void Parse(StringReader reader, Configuration config) { var currentSection = new Section(Section.DefaultSectionName); var preCommentBuilder = new StringBuilder(); - HashSet validCommentChars = new HashSet(Configuration.ValidCommentChars); // Initialize once for each reader to optimize performance var lineNumber = 0; string line; @@ -44,7 +42,7 @@ private static void Parse(StringReader reader, Configuration config) continue; } - var comment = ParseComment(line, validCommentChars, out int commentIndex); + var comment = ParseComment(line, out int commentIndex); if (commentIndex == 0) { @@ -111,7 +109,7 @@ private static void Parse(StringReader reader, Configuration config) } } - private static string ParseComment(string line, HashSet validCommentChars, out int commentCharIndex) + private static string ParseComment(string line, out int commentCharIndex) { // A comment starts with a valid comment character that: // 1. is not within a quote (eg. "this is # not a comment"), and @@ -130,7 +128,7 @@ private static string ParseComment(string line, HashSet validCommentChars, while (index < length) // traverse line from left to right { var currentChar = line[index]; - var isValidCommentChar = validCommentChars.Contains(currentChar); + var isValidCommentChar = Configuration.ValidCommentChars.Contains(currentChar); var isQuotationMark = currentChar == '\"'; var isCharWithinQuotes = (quoteCount & 1) == 1; // bitwise AND is slightly faster var isCharEscaped = index > 0 && line[index - 1] == '\\'; diff --git a/Src/Setting.cs b/Src/Setting.cs index fdfa459..307b857 100644 --- a/Src/Setting.cs +++ b/Src/Setting.cs @@ -2,6 +2,7 @@ // https://sharpconfig.org using System; +using System.Linq; using System.Text; namespace SharpConfig @@ -612,8 +613,10 @@ private static string GetValueForOutput(string rawValue) return rawValue; } + bool isAnyCommentCharInRawValue() => rawValue.Any(c => Configuration.ValidCommentChars.Contains(c)); + if (rawValue.IndexOf(" ", StringComparison.Ordinal) >= 0 || - (rawValue.IndexOfAny(Configuration.ValidCommentChars) >= 0 && !Configuration.IgnoreInlineComments)) + (isAnyCommentCharInRawValue() && !Configuration.IgnoreInlineComments)) { rawValue = "\"" + rawValue + "\""; }