Files
swift-mirror/benchmark/multi-source/Monoids/Trie.swift
2025-07-23 17:26:48 -04:00

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
}
}