Skip to content

Commit d0e2b22

Browse files
committed
Simplify .range(of:) and SearchCache.
1 parent f68afb2 commit d0e2b22

File tree

2 files changed

+24
-17
lines changed

2 files changed

+24
-17
lines changed

Sources/Patterns/General/General.swift

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,20 @@
77

88
@usableFromInline
99
struct SearchCache<Element: Hashable> {
10-
@usableFromInline
11-
let length: Int
1210
@usableFromInline
1311
let skipTable: [Element: Int]
14-
// TODO: Store pattern in array
12+
@usableFromInline
13+
let target: [Element]
1514

1615
@usableFromInline
17-
init<Target: BidirectionalCollection>(_ target: Target)
18-
where Target.SubSequence.Element == Element {
19-
length = target.count
20-
var skipTable = [Element: Int](minimumCapacity: length)
21-
for (i, c) in target.dropLast().enumerated() {
22-
skipTable[c] = length - i - 1
16+
init<Target: Sequence>(_ target: Target) where Target.Element == Element {
17+
let newtarget = Array(target)
18+
var skipTable = [Element: Int](minimumCapacity: newtarget.count)
19+
for (i, c) in newtarget[...].dropLast().enumerated() {
20+
skipTable[c] = newtarget.count - i - 1
2321
}
2422
self.skipTable = skipTable
23+
self.target = newtarget
2524
}
2625
}
2726

@@ -30,17 +29,25 @@ extension BidirectionalCollection where Element: Hashable {
3029
/// - Parameters:
3130
/// - target: The sequence of elements to search for.
3231
/// - start: Where to start the search from.
33-
/// - cache: When searching for the same sequence multiple times, use a SearchCache for improved performance.
3432
/// - Returns: The range where `target` was found, or nil if not found.
3533
@inlinable
36-
func range<Target: BidirectionalCollection>
37-
(of target: Target, from start: Index? = nil, cache: SearchCache<Target.Element>? = nil) -> Range<Index>?
34+
func range<Target: Sequence>(of target: Target, from start: Index? = nil) -> Range<Index>?
3835
where Target.Element == Element {
36+
self.range(of: SearchCache(target), from: start)
37+
}
38+
39+
/// Finds the next occurrence of `cache.target` in this collection, using the pre-created `cache`.
40+
/// - Parameters:
41+
/// - cache: When searching for the same sequence multiple times, use a SearchCache for improved performance.
42+
/// - start: Where to start the search from.
43+
/// - Returns: The range where `target` was found, or nil if not found.
44+
@inlinable
45+
func range(of cache: SearchCache<Element>, from start: Index? = nil) -> Range<Index>? {
3946
// https://en.wikipedia.org/wiki/Boyer–Moore–Horspool_algorithm
40-
let cache = cache ?? SearchCache(target)
41-
guard cache.length > 0 else { return nil }
47+
let target = cache.target
48+
guard !target.isEmpty else { return nil }
4249

43-
var pos = self.index(start ?? self.startIndex, offsetBy: cache.length - 1, limitedBy: endIndex) ?? endIndex
50+
var pos = self.index(start ?? self.startIndex, offsetBy: target.count - 1, limitedBy: endIndex) ?? endIndex
4451

4552
while pos < endIndex {
4653
var i = pos
@@ -55,7 +62,7 @@ extension BidirectionalCollection where Element: Hashable {
5562
}
5663
}
5764

58-
let advance = cache.skipTable[self[pos]] ?? cache.length
65+
let advance = cache.skipTable[self[pos]] ?? target.count
5966
pos = self.index(pos, offsetBy: advance, limitedBy: endIndex) ?? endIndex
6067
}
6168

Sources/Patterns/Operations on Patterns/Skip.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ extension MutableCollection where Self: RandomAccessCollection, Self: RangeRepla
7070
} else {
7171
let cache = SearchCache(elements)
7272
self[skipIndex] = .search { input, index in
73-
input.range(of: elements, from: index, cache: cache)?.upperBound
73+
input.range(of: cache, from: index)?.upperBound
7474
}
7575
self[searchablesStartAt] = .choice(offset: -1, atIndexOffset: (-elements.count) + 1)
7676
self[searchablesStartAt + 1] = .jump(offset: elements.count - 1)

0 commit comments

Comments
 (0)