Skip to content

Instantly share code, notes, and snippets.

@airspeedswift
Last active March 5, 2017 13:20
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save airspeedswift/71f15d1eb866be9e5ac7 to your computer and use it in GitHub Desktop.
Save airspeedswift/71f15d1eb866be9e5ac7 to your computer and use it in GitHub Desktop.
Swift copy-on-write behaviour for a struct using HeapBuffer
// 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
private typealias Node = _Node<T>
private var _root: Node? = nil
public init() { }
// constructor from a sequence
public init<S: SequenceType where S.Generator.Element == T>(_ seq: S) {
var g = seq.generate()
while let x: T = g.next() {
self.insert(x)
}
}
// check root node to see if the Tree's been copied,
// and if it has, replicate itself...
private mutating func ensureUnique() {
if !isUniquelyReferencedNonObjC(&_root) {
println("copying myself")
// 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: SequenceType {
typealias Generator = GeneratorOf<T>
public func generate() -> Generator {
var stack: [Node] = []
var current: Node? = _root
return GeneratorOf {
// 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
}
}
}
}
}
extension Tree: Printable {
public var description: String {
return "[" + ", ".join(lazy(self).map(toString)) + "]"
}
}
var tree = Tree<String>()
tree.insert("Emily")
tree.insert("Thomas")
var tree2 = tree
println("Copied tree2")
println("Now changing tree")
tree.insert("Gordon")
tree.insert("James")
tree.insert("James")
tree.insert("Henry")
tree.contains("Thomas")
tree.contains("Gordon")
tree.contains("Henry")
tree.contains("James")
tree.contains("Spencer")
tree.contains("Gordon")
tree2.contains("Gordon")
var tree3 = tree2
println("Now changing tree3")
tree3.insert("The Fat Controler")
println(tree)
println(tree2)
println(tree3)
isUniquelyReferencedNonObjC(&tree._root)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment