// 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() var tree2 = Tree() var tree3 = Tree() for _ in 1...50*n { tree1 = Tree() 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, _ t2: Tree, _ t3: Tree) -> 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 { var _value: T var _left: _Node? = nil var _right: _Node? = nil init(value: T) { _value = value } } public struct Tree { // this makes things a bit more pleasant later fileprivate typealias Node = _Node fileprivate var _root: Node? = nil public init() { } // constructor from a sequence public init(_ 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(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 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 } } } } }