-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathCOWTree.swift
149 lines (129 loc) · 3.29 KB
/
COWTree.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// COWTree benchmark
//
// Description: Copy-On-Write behaviour for a struct
// Source: https://gist.github.com/airspeedswift/71f15d1eb866be9e5ac7
import TestsUtils
public let benchmarks = [
BenchmarkInfo(
name: "COWTree",
runFunction: run_COWTree,
tags: [.validation, .abstraction, .String],
legacyFactor: 20
),
]
@inline(never)
public func run_COWTree(_ n: Int) {
var tree1 = Tree<String>()
var tree2 = Tree<String>()
var tree3 = Tree<String>()
for _ in 1...50*n {
tree1 = Tree<String>()
tree1.insert("Emily")
tree2 = tree1
tree1.insert("Gordon")
tree3 = tree2
tree3.insert("Spencer")
if !checkRef(tree1, tree2, tree3) {
break
}
}
check(checkRef(tree1, tree2, tree3))
}
@inline(never)
func checkRef(_ t1: Tree<String>, _ t2: Tree<String>,
_ t3: Tree<String>) -> Bool {
if !(t1.contains("Emily") && t1.contains("Gordon") &&
!t1.contains("Spencer")) {
return false
}
if !(t2.contains("Emily") && !t2.contains("Gordon") &&
!t2.contains("Spencer")) {
return false
}
if !(t3.contains("Emily") && !t3.contains("Gordon") &&
t3.contains("Spencer")) {
return false
}
return true
}
// ideally we would define this inside the tree struct
private class _Node<T: Comparable> {
var _value: T
var _left: _Node<T>? = nil
var _right: _Node<T>? = nil
init(value: T) { _value = value }
}
public struct Tree<T: Comparable> {
// this makes things a bit more pleasant later
fileprivate typealias Node = _Node<T>
fileprivate var _root: Node? = nil
public init() { }
// constructor from a sequence
public init<S: Sequence>(_ seq: S) where S.Element == T {
var g = seq.makeIterator()
while let x = g.next() {
self.insert(x)
}
}
private mutating func ensureUnique() {
if !isKnownUniquelyReferenced(&_root) {
// inefficiently...
self = Tree<T>(self)
}
}
public mutating func insert(_ value: T) {
ensureUnique()
_root = insert(_root, value)
}
private mutating func insert(_ node: Node?, _ value: T) -> Node? {
switch node {
case .none:
return Node(value: value)
case let .some(node) where value < node._value:
node._left = insert(node._left, value)
return node
case let .some(node):
node._right = insert(node._right, value)
return node
}
}
public func contains(_ value: T) -> Bool {
return contains(_root, value)
}
private func contains(_ node: Node?, _ value: T) -> Bool {
switch node {
case .none:
return false
case let .some(node) where node._value == value:
return true
case let .some(node):
return contains(value < node._value ? node._left : node._right,
value)
}
}
}
extension Tree: Sequence {
public typealias Iterator = AnyIterator<T>
public func makeIterator() -> Iterator {
var stack: [Node] = []
var current: Node? = _root
return AnyIterator {
// stack-based technique for inorder traversal
// without recursion
while true {
if let node = current {
stack.append(node)
current = node._left
}
else if !stack.isEmpty {
let pop = stack.removeLast()
current = pop._right
return pop._value
}
else {
return nil
}
}
}
}
}