refactor glob matcher (& improve performance)

This commit is contained in:
2024-11-22 21:47:16 +11:00
parent be51934334
commit 2eea15fb90

View File

@ -7,25 +7,33 @@ import Foundation
import ArgumentParser import ArgumentParser
struct GlobMatcher: PatternMatcher { struct GlobMatcher: PatternMatcher {
private let _patterns: [String] private let _patterns: [Pattern]
private let _flags: Int32 private let _flags: Int32
init(patterns: [String], ignoreCase: Bool) throws(ArgumentParser.ExitCode) { init(patterns: [String], ignoreCase: Bool) throws(ArgumentParser.ExitCode) {
self._patterns = patterns // Quick hack to make matching without explicit globs easier
let globChars = CharacterSet(charactersIn: "*?[]")
self._patterns = patterns.map { pattern in
if pattern.unicodeScalars.contains(where: globChars.contains) {
.wildcard(glob: pattern)
} else {
.globless(match: pattern)
}
}
self._flags = ignoreCase ? FNM_CASEFOLD : 0 self._flags = ignoreCase ? FNM_CASEFOLD : 0
} }
func match(_ field: String) -> Bool { func match(_ field: String) -> Bool {
for pattern in self._patterns { for pattern in self._patterns {
// Quick hack to make matching without explicit globs easier switch pattern {
if pattern.rangeOfCharacter(from: .init(charactersIn: "*?[]")) == nil { case .globless(let match):
if self._flags & FNM_CASEFOLD != 0 { if self._flags & FNM_CASEFOLD != 0 {
return field.localizedCaseInsensitiveContains(pattern) return field.localizedCaseInsensitiveContains(match)
} else { } else {
return field.contains(pattern) return field.contains(match)
} }
} case .wildcard(let glob):
let res = fnmatch(pattern, field, self._flags) let res = fnmatch(glob, field, self._flags)
if res == FNM_NOMATCH { if res == FNM_NOMATCH {
continue continue
} else if res == 0 { } else if res == 0 {
@ -33,6 +41,14 @@ struct GlobMatcher: PatternMatcher {
} }
fatalError("fnmatch error \(res)") fatalError("fnmatch error \(res)")
} }
}
return false return false
} }
} }
private extension GlobMatcher {
enum Pattern {
case wildcard(glob: String)
case globless(match: String)
}
}