mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
137 lines
3.4 KiB
Swift
137 lines
3.4 KiB
Swift
struct Trie {
|
|
typealias Node = Int16
|
|
|
|
var values: [Node] = []
|
|
var children: [Node] = []
|
|
var freeList: [Node] = []
|
|
|
|
let emptyNode: [Node]
|
|
|
|
init(alphabet: Int) {
|
|
self.emptyNode = Array(repeating: -1, count: alphabet)
|
|
_ = try! createNode() // The root node
|
|
}
|
|
|
|
mutating func createNode() throws(RewritingError) -> Node {
|
|
if !freeList.isEmpty {
|
|
let result = Int(freeList.removeLast())
|
|
values.replaceSubrange(result ..< result + emptyNode.count, with: emptyNode)
|
|
children.replaceSubrange(result ..< result + emptyNode.count, with: emptyNode)
|
|
return Node(result)
|
|
}
|
|
|
|
let result = values.count
|
|
if result + emptyNode.count >= 32000 {
|
|
throw RewritingError.tooManyNodes
|
|
}
|
|
values.append(contentsOf: emptyNode)
|
|
children.append(contentsOf: emptyNode)
|
|
precondition(values.count == children.count)
|
|
precondition(values.count % emptyNode.count == 0)
|
|
return Node(result)
|
|
}
|
|
|
|
mutating func reclaimNode(_ node: Node) {
|
|
freeList.append(node)
|
|
}
|
|
|
|
mutating func insert(_ key: Word, _ value: Int) throws(RewritingError) {
|
|
var node = 0
|
|
for i in 0 ..< key.count - 1 {
|
|
let s = key[i]
|
|
if children[node + Int(s)] == -1 {
|
|
children[node + Int(s)] = try createNode()
|
|
}
|
|
node = Int(children[node + Int(s)])
|
|
}
|
|
values[node + Int(key.last!)] = Node(value)
|
|
}
|
|
|
|
func lookup(_ key: Word, _ i: Int) -> Int? {
|
|
var node = 0
|
|
for s in key[i ..< key.count] {
|
|
let n = Int(values[node + Int(s)])
|
|
if n != -1 { return n }
|
|
node = Int(children[node + Int(s)])
|
|
if node == -1 { return nil }
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Visits all keys that are equal to a prefix of key[i ...], as well as
|
|
// all keys whose prefix is equal to key[i ...].
|
|
func visitOverlaps(_ key: Word, _ from: Int, callback: (Int) -> ()) {
|
|
var node = 0
|
|
for s in key[from...] {
|
|
let n = Int(values[node + Int(s)])
|
|
if n != -1 { callback(n) }
|
|
node = Int(children[node + Int(s)])
|
|
if node == -1 { return }
|
|
}
|
|
|
|
if node == 0 { return }
|
|
|
|
var stack: [Int] = [node]
|
|
|
|
repeat {
|
|
let node = stack.removeLast()
|
|
|
|
for s in (0 ..< emptyNode.count) {
|
|
let n = Int(values[node + s])
|
|
if n != -1 { callback(n) }
|
|
let child = Int(children[node + s])
|
|
if child != -1 { stack.append(child) }
|
|
}
|
|
} while !stack.isEmpty
|
|
}
|
|
|
|
func isEmptyNode(_ node: Int) -> Bool {
|
|
for i in 0 ..< emptyNode.count {
|
|
if values[node + i] != -1 ||
|
|
children[node + i] != -1 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
mutating func remove(_ key: Word, _ value: Int) {
|
|
var node = 0
|
|
var stack: [Int] = [] // path to current node from root
|
|
|
|
for i in 0 ..< key.count - 1 {
|
|
let s = key[i]
|
|
precondition(children[node + Int(s)] != -1)
|
|
|
|
stack.append(node)
|
|
node = Int(children[node + Int(s)])
|
|
}
|
|
|
|
let j = node + Int(key.last!)
|
|
precondition(values[j] == value)
|
|
values[j] = -1
|
|
|
|
// Remove any newly-empty nodes, up to the root.
|
|
repeat {
|
|
if !isEmptyNode(node) { return }
|
|
|
|
reclaimNode(Node(node))
|
|
|
|
let parent = stack.removeLast()
|
|
|
|
var sawThis = false
|
|
for i in 0 ..< emptyNode.count {
|
|
if Int(children[parent + i]) == node {
|
|
children[parent + i] = -1
|
|
sawThis = true
|
|
break
|
|
}
|
|
}
|
|
precondition(sawThis)
|
|
|
|
node = parent
|
|
} while !stack.isEmpty
|
|
}
|
|
}
|