From 927ccee61374c23d014283dbbbd4758e812f93fa Mon Sep 17 00:00:00 2001 From: Kurt Date: Thu, 3 Jun 2021 17:24:45 -0700 Subject: [PATCH] Cache all created regexes Regex objects aren't cheap, and the RegexCache has DefaultMaxCacheSize = 15. We're checking 4,000 regexes for each unique string, so just keep the created regexes around instead of cycling new through the cache. +4MB passive consumption, but each IsFiltered call no longer generates >4MB of discarded objects. My unit tests run >25% faster now... nice?! --- .../Legality/Restrictions/WordFilter.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/PKHeX.Core/Legality/Restrictions/WordFilter.cs b/PKHeX.Core/Legality/Restrictions/WordFilter.cs index 952960807..3428b82c6 100644 --- a/PKHeX.Core/Legality/Restrictions/WordFilter.cs +++ b/PKHeX.Core/Legality/Restrictions/WordFilter.cs @@ -9,9 +9,21 @@ namespace PKHeX.Core public static class WordFilter { /// - /// Source pattern regexes to check with + /// Regex patterns to check against /// - private static readonly string[] Patterns = Util.GetStringList("badwords"); + /// No need to keep the original pattern strings around; the object retrieves this via + private static readonly Regex[] Regexes = LoadPatterns(Util.GetStringList("badwords")); + + // if you're running this as a server and don't mind a few extra seconds of startup, add RegexOptions.Compiled for slightly better checking. + private const RegexOptions Options = RegexOptions.CultureInvariant; + + private static Regex[] LoadPatterns(IReadOnlyList patterns) + { + var result = new Regex[patterns.Count]; + for (int i = 0; i < patterns.Count; i++) + result[i] = new Regex(patterns[i], Options); + return result; + } /// /// Due to some messages repeating (Trainer names), keep a list of repeated values for faster lookup. @@ -43,13 +55,13 @@ public static bool IsFiltered(string message, out string regMatch) } // not in dictionary, check patterns - foreach (var pattern in Patterns) + foreach (var regex in Regexes) { - if (!Regex.IsMatch(msg, pattern)) + if (!regex.IsMatch(msg)) continue; // match found, cache result - regMatch = pattern; + regMatch = regex.ToString(); // fetches from regex field lock (dictLock) Lookup[msg] = regMatch; return true;