optimization: faster mask matching
Massimo Melina committed
Feb 16, 2025 at 14:23 UTC
d47f0873a454e15ebf5f18fef78029fc2074d481
3 files changed
+7
-3
src/cross.ts
+3
-1
@@ -465,8 +465,10 @@ export function makeMatcher(mask: string, emptyMaskReturns=false) {
465
: () => emptyMaskReturns
466
}
467
468
+// this is caching all matchers, so don't use it with frequently changing masks. Benchmarks revealed that _.memoize make it slower than not using it, while this simple cache can speed up to 30x
469
export function matches(s: string, mask: string, emptyMaskReturns=false) {
469
- return makeMatcher(mask, emptyMaskReturns)(s)
470
+ const cache = (matches as any).cache ||= {}
471
+ return (cache[mask + (emptyMaskReturns ? '1' : '0')] ||= makeMatcher(mask, emptyMaskReturns))(s)
472
}
473
474
// if delimiter is specified, it is prefixed to symbols. If it contains a space, the part after the space is considered as suffix.
src/geo.ts
+1
@@ -14,6 +14,7 @@ const allowUnknown = defineConfig(CFG.geo_allow_unknown, false)
14
enabled.sub(checkFiles)
15
setInterval(checkFiles, DAY) // keep updated at run-time
16
17
+// benchmark: memoize can make this 44x faster
18
export const ip2country = _.memoize((ip: string) => ip2location.getCountryShortAsync(ip).then(v => v === '-' ? '' : v, () => ''))
19
20
export const geoFilter: Middleware = async (ctx, next) => {
src/misc.ts
+3
-2
@@ -33,9 +33,10 @@ export function isLocalHost(c: Connection | Koa.Context | string) {
33
return ip && isIpLocalHost(ip)
34
}
35
36
-// this will memory-leak over mask, so be careful with what you use this
36
+// this will memory-leak over mask, so be careful with what you use this. Object is 3x faster than _.memoize
37
export function netMatches(ip: string, mask: string, emptyMaskReturns=false) {
38
- return _.memoize(makeNetMatcher, (a,b) => `${a}\t${b ? 1 : 0}`)(mask, emptyMaskReturns)(ip) // cache the matcher
38
+ const cache = (netMatches as any).cache ||= {}
39
+ return (cache[mask + (emptyMaskReturns ? '1' : '0')] ||= makeNetMatcher(mask, emptyMaskReturns))(ip) // cache the matcher
40
}
41
export function makeNetMatcher(mask: string, emptyMaskReturns=false) {
42
if (!mask)