├── .gitignore ├── Images ├── Attabench-screenshot.png ├── Slides.swift ├── Title Slide.jpeg └── cover@2x.png ├── LICENSE.md ├── Package.swift ├── README.md └── Sources ├── BTree.swift ├── BTree2.swift ├── BTree3.swift ├── BTree4.swift ├── NSOrderedSet.swift ├── Preface.swift ├── RedBlackTree.swift ├── RedBlackTree2.swift ├── SillySet.swift ├── SortedArray.swift ├── SortedSet.swift └── main.swift /.gitignore: -------------------------------------------------------------------------------- 1 | /.build 2 | -------------------------------------------------------------------------------- /Images/Attabench-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objcio/OptimizingCollections/a44dc3bf0770aa6ade11127ae466e8fa60e7af76/Images/Attabench-screenshot.png -------------------------------------------------------------------------------- /Images/Slides.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Slides.swift 3 | // 4 | // Copyright © 2017 Károly Lőrentey. 5 | // 6 | 7 | // This file contains the raw source code that I presented on my slides. 8 | // The slides were put together by taking manual screenshots of this file as displayed by Xcode. 9 | // This approach was rather labor intensive, but it did produce nicely syntax highlighted code. 10 | // I wouldn't recommend doing this, though -- changing stuff was not fun at all. :-) 11 | 12 | import Foundation 13 | 14 | //protocol OrderedSet { 15 | // associatedtype Element: Comparable 16 | // 17 | // init() 18 | // 19 | // func forEach(_ body: (Element) throws -> Void) rethrows 20 | // 21 | // @discardableResult 22 | // mutating func insert(_ newElement: Element) 23 | // -> (inserted: Bool, memberAfterInsert: Element) 24 | // 25 | // func contains(_ element: Element) -> Bool 26 | //} 27 | 28 | protocol OrderedSet { 29 | associatedtype Element: Comparable 30 | 31 | init() 32 | func forEach(_ body: (Element) -> Void) 33 | mutating func insert(_ newElement: Element) 34 | } 35 | 36 | 37 | /*******************************************************************/ 38 | //MARK: NSOrderedSet 39 | 40 | class MyOrderedSet: OrderedSet { 41 | let storage = NSMutableOrderedSet() 42 | 43 | required init() {} 44 | 45 | static func compare(_ a: Any, _ b: Any) -> ComparisonResult { 46 | let a = a as! Element, b = b as! Element 47 | return a < b ? .orderedAscending 48 | : a > b ? .orderedDescending 49 | : .orderedSame 50 | } 51 | 52 | func insert(_ newElement: Element) { 53 | let index = storage.index( 54 | of: newElement, inSortedRange: NSRange(0 ..< storage.count), 55 | options: .insertionIndex, usingComparator: MyOrderedSet.compare) 56 | storage.insert(newElement, at: index) 57 | } 58 | 59 | func forEach(_ body: (Element) -> Void) { 60 | storage.forEach { body($0 as! Element) } 61 | } 62 | } 63 | 64 | 65 | do { 66 | var set = MyOrderedSet() 67 | set.insert(9) 68 | set.insert(5) 69 | set.insert(12) 70 | set.insert(2) 71 | set.forEach { print($0) } 72 | } 73 | 74 | /*******************************************************************/ 75 | //MARK: SortedArray 76 | 77 | struct SortedArray: OrderedSet { 78 | var storage: [Element] = [] 79 | 80 | func forEach(_ body: (Element) -> Void) { 81 | storage.forEach(body) 82 | } 83 | } 84 | 85 | extension SortedArray: RandomAccessCollection { 86 | typealias Indices = CountableRange 87 | 88 | var startIndex: Int { return 0 } 89 | var endIndex: Int { return storage.count } 90 | 91 | subscript(_ i: Int) -> Element { return storage[i] } 92 | } 93 | 94 | extension SortedArray { 95 | func slot(of element: Element) -> Int { 96 | var i = 0 97 | var j = storage.count 98 | while i < j { 99 | let middle = i + (j - i) / 2 100 | if element > storage[middle] { 101 | i = middle + 1 102 | } 103 | else { 104 | j = middle 105 | } 106 | } 107 | return i 108 | } 109 | } 110 | 111 | extension SortedArray { 112 | mutating func insert(_ newElement: Element) { 113 | let slot = self.slot(of: newElement) 114 | if slot == storage.count || storage[slot] != newElement { 115 | storage.insert(newElement, at: slot) 116 | } 117 | } 118 | } 119 | 120 | extension SortedArray { 121 | func contains(_ element: Element) -> Bool { 122 | let slot = self.slot(of: element) 123 | return slot < storage.count && storage[slot] == element 124 | } 125 | } 126 | 127 | /*******************************************************************/ 128 | // MARK: Algebraic Red-Black Tree 129 | 130 | enum Color { 131 | case black 132 | case red 133 | } 134 | 135 | enum AlgebraicTree { 136 | case empty 137 | indirect case node(Color, AlgebraicTree, Element, AlgebraicTree) 138 | } 139 | 140 | extension AlgebraicTree: CustomStringConvertible { 141 | var hasChildren: Bool { 142 | guard case let .node(_, left, _, right) = self else { return false } 143 | guard case .empty = left else { return true } 144 | guard case .empty = right else { return true } 145 | return false 146 | } 147 | private func visitLines(_ leftPrefix: String, _ rootPrefix: String, _ rightPrefix: String, _ body: (String) -> Void) { 148 | guard case let .node(color, left, value, right) = self else { 149 | body(rootPrefix + "▪︎") 150 | return 151 | } 152 | guard hasChildren else { body(rootPrefix + "\(color) \(value)"); return } 153 | left.visitLines(leftPrefix + " ", 154 | leftPrefix + "┌─── ", 155 | leftPrefix + "│ ", 156 | body) 157 | body(rootPrefix + "\(color) \(value)") 158 | right.visitLines(rightPrefix + "│ ", 159 | rightPrefix + "└─── ", 160 | rightPrefix + " ", 161 | body) 162 | } 163 | var description: String { 164 | var result = "" 165 | self.visitLines("l", ".", "r") { line in result += line; result += "\n" } 166 | return result 167 | } 168 | } 169 | 170 | let tree: AlgebraicTree = 171 | .node(.black, 172 | .node(.red, 173 | .node(.black, 174 | .empty, 175 | 1, 176 | .node(.red, .empty, 4, .empty)), 177 | 5, 178 | .node(.black, .empty, 8, .empty)), 179 | 9, 180 | .node(.red, 181 | .node(.black, .empty, 11, .empty), 182 | 12, 183 | .node(.black, 184 | .node(.red, .empty, 14, .empty), 185 | 16, 186 | .node(.red, .empty, 17, .empty)))) 187 | 188 | let a = AlgebraicTree.empty 189 | let b = AlgebraicTree.empty 190 | let c = AlgebraicTree.empty 191 | let d = AlgebraicTree.empty 192 | let x = 1 193 | let y = 2 194 | let z = 3 195 | 196 | print("Foo \(a)") 197 | print("Foo \(tree)") 198 | 199 | let n1: AlgebraicTree = 200 | 201 | .node(.black, .node(.red, .node(.red, a, x, b), y, c), z, d) 202 | 203 | let n2: AlgebraicTree = 204 | 205 | .node(.black, .node(.red, a, x, .node(.red, b, y, c)), z, d) 206 | 207 | let n3: AlgebraicTree = 208 | 209 | .node(.black, a, x, .node(.red, .node(.red, b, y, c), z, d)) 210 | 211 | 212 | let n4: AlgebraicTree = 213 | 214 | .node(.black, a, x, .node(.red, b, y, .node(.red, c, z, d))) 215 | 216 | let n5: AlgebraicTree = 217 | 218 | .node(.red, .node(.black, a, x, b), y, .node(.black, c, z, d)) 219 | 220 | 221 | extension AlgebraicTree { 222 | func forEach(_ body: (Element) -> Void) { 223 | switch self { 224 | case .empty: 225 | return 226 | case let .node(_, left, value, right): 227 | left.forEach(body) 228 | body(value) 229 | right.forEach(body) 230 | } 231 | } 232 | } 233 | 234 | extension AlgebraicTree { 235 | func contains(_ element: Element) -> Bool { 236 | switch self { 237 | case .empty: 238 | return false 239 | case let .node(_, _, value, _) where element == value: 240 | return true 241 | case let .node(_, left, value, _) where element < value: 242 | return left.contains(element) 243 | case let .node(_, _, _, right): 244 | return right.contains(element) 245 | } 246 | } 247 | } 248 | 249 | extension AlgebraicTree { 250 | func _inserting(_ new: Element) -> AlgebraicTree { 251 | switch self { 252 | case .empty: 253 | // Replace the empty tree with a single node. 254 | return .node(.red, .empty, new, .empty) 255 | 256 | case let .node(_, _, value, _) where new == value: 257 | // The value was already in the tree; we're done. 258 | return self 259 | 260 | case let .node(color, left, value, right) where new < value: 261 | // Insert the new value to the left child. 262 | return balanced(color, left._inserting(new), value, right) 263 | 264 | case let .node(color, left, value, right): // new > value 265 | // Insert the new value to the right child. 266 | return balanced(color, left, value, right._inserting(new)) 267 | } 268 | } 269 | } 270 | 271 | 272 | extension AlgebraicTree { 273 | func balanced(_ color: Color, 274 | _ left: AlgebraicTree, 275 | _ value: Element, 276 | _ right: AlgebraicTree) -> AlgebraicTree { 277 | switch (color, left, value, right) { 278 | case let (.black, .node(.red, .node(.red, a, x, b), y, c), z, d), 279 | let (.black, .node(.red, a, x, .node(.red, b, y, c)), z, d), 280 | let (.black, a, x, .node(.red, .node(.red, b, y, c), z, d)), 281 | let (.black, a, x, .node(.red, b, y, .node(.red, c, z, d))): 282 | return .node(.red, .node(.black, a, x, b), y, .node(.black, c, z, d)) 283 | default: 284 | return .node(color, left, value, right) 285 | } 286 | } 287 | } 288 | 289 | // The insert algorithm below is a simple transliteration of the 290 | // algorithm in Chris Okasaki's 1999 paper, "Red-black trees in a functional setting". 291 | // doi:10.1017/S0956796899003494 292 | 293 | 294 | extension AlgebraicTree { 295 | func inserting(_ element: Element) -> AlgebraicTree { 296 | switch self._inserting(element) { 297 | case let .node(.red, left, value, right): 298 | return .node(.black, left, value, right) 299 | case let result: 300 | return result 301 | } 302 | } 303 | 304 | mutating func insert(_ element: Element) { 305 | self = self.inserting(element) 306 | } 307 | } 308 | 309 | /*******************************************************************/ 310 | //MARK: COWTree 311 | 312 | /// A red-black tree with value semantics and copy-on-write optimization. 313 | struct COWTree { 314 | var root: COWNode? = nil 315 | } 316 | 317 | final class COWNode { 318 | var color: Color 319 | var left: COWNode? = nil 320 | var value: Element 321 | var right: COWNode? = nil 322 | 323 | init(_ color: Color, _ left: COWNode?, 324 | _ value: Element, _ right: COWNode?) { 325 | self.color = color 326 | self.left = left 327 | self.value = value 328 | self.right = right 329 | } 330 | } 331 | 332 | extension COWTree { 333 | public func forEach(_ body: (Element) -> Void) { 334 | root?.forEach(body) 335 | } 336 | } 337 | 338 | extension COWNode { 339 | func forEach(_ body: (Element) -> Void) { 340 | left?.forEach(body) 341 | body(value) 342 | right?.forEach(body) 343 | } 344 | } 345 | 346 | extension COWTree { 347 | public func contains(_ element: Element) -> Bool { 348 | var node = root 349 | while let n = node { 350 | if n.value < element { 351 | node = n.right 352 | } 353 | else if n.value > element { 354 | node = n.left 355 | } 356 | else { 357 | return true 358 | } 359 | } 360 | return false 361 | } 362 | } 363 | 364 | extension COWTree { 365 | mutating func makeRootUnique() -> COWNode? { 366 | if root != nil, !isKnownUniquelyReferenced(&root) { 367 | root = root!.clone() 368 | } 369 | return root 370 | } 371 | } 372 | 373 | extension COWNode { 374 | func clone() -> COWNode { 375 | return COWNode(color, left, value, right) 376 | } 377 | } 378 | 379 | extension COWNode { 380 | func makeLeftUnique() -> COWNode? { 381 | if left != nil, !isKnownUniquelyReferenced(&left) { 382 | left = left!.clone() 383 | } 384 | return left 385 | } 386 | 387 | func makeRightUnique() -> COWNode? { 388 | if right != nil, !isKnownUniquelyReferenced(&right) { 389 | right = right!.clone() 390 | } 391 | return right 392 | } 393 | } 394 | 395 | extension COWTree { 396 | public mutating func insert(_ element: Element) { 397 | switch makeRootUnique() { 398 | case .none: 399 | self.root = COWNode(.black, nil, element, nil) 400 | case .some(let node): 401 | node.insert(element) 402 | node.color = .black 403 | } 404 | } 405 | } 406 | 407 | extension COWNode { 408 | func insert(_ element: Element) { 409 | if element < self.value { 410 | if let next = makeLeftUnique() { 411 | next.insert(element) 412 | self.balance() 413 | } 414 | else { 415 | self.left = COWNode(.red, nil, element, nil) 416 | } 417 | } 418 | else if element > self.value { 419 | if let next = makeRightUnique() { 420 | next.insert(element) 421 | self.balance() 422 | } 423 | else { 424 | self.right = COWNode(.red, nil, element, nil) 425 | } 426 | } 427 | } 428 | } 429 | 430 | extension COWNode { 431 | func balance() { 432 | if self.color == .red { return } 433 | if left?.color == .red { 434 | if left?.left?.color == .red { 435 | let l = left! 436 | let ll = l.left! 437 | swap(&self.value, &l.value) 438 | (self.left, l.left, l.right, self.right) 439 | = (ll, l.right, self.right, l) 440 | self.color = .red 441 | l.color = .black 442 | ll.color = .black 443 | return 444 | } 445 | if left?.right?.color == .red { 446 | let l = left! 447 | let lr = l.right! 448 | swap(&self.value, &lr.value) 449 | (l.right, lr.left, lr.right, self.right) 450 | = (lr.left, lr.right, self.right, lr) 451 | self.color = .red 452 | l.color = .black 453 | lr.color = .black 454 | return 455 | } 456 | } 457 | if right?.color == .red { 458 | if right?.left?.color == .red { 459 | let r = right! 460 | let rl = r.left! 461 | swap(&self.value, &rl.value) 462 | (self.left, rl.left, rl.right, r.left) 463 | = (rl, self.left, rl.left, rl.right) 464 | self.color = .red 465 | r.color = .black 466 | rl.color = .black 467 | return 468 | } 469 | if right?.right?.color == .red { 470 | let r = right! 471 | let rr = r.right! 472 | swap(&self.value, &r.value) 473 | (self.left, r.left, r.right, self.right) 474 | = (r, self.left, r.left, rr) 475 | self.color = .red 476 | r.color = .black 477 | rr.color = .black 478 | return 479 | } 480 | } 481 | } 482 | } 483 | 484 | /*******************************************************************/ 485 | //MARK: BTree 486 | 487 | let l1CacheSize = 32_768 488 | 489 | struct BTree { 490 | typealias Node = BTreeNode 491 | var root: Node 492 | 493 | init(order: Int) { 494 | self.root = Node(order: order) 495 | } 496 | 497 | init() { 498 | let elementSize = MemoryLayout.stride 499 | self.init(order: max(8, l1CacheSize / 2 / elementSize)) 500 | } 501 | } 502 | 503 | final class BTreeNode { 504 | let order: Int 505 | var elementCount: Int 506 | let elements: UnsafeMutablePointer 507 | let children: UnsafeMutablePointer? 508 | 509 | init(order: Int = 1024, leaf: Bool = true) { 510 | self.order = order 511 | self.elementCount = 0 512 | self.elements = .allocate(capacity: order) 513 | self.children = leaf ? nil : .allocate(capacity: order) 514 | } 515 | 516 | deinit { 517 | elements.deinitialize(count: elementCount) 518 | elements.deallocate(capacity: order) 519 | if let children = self.children { 520 | children.deinitialize(count: elementCount + 1) 521 | children.deallocate(capacity: order) 522 | } 523 | } 524 | } 525 | 526 | extension BTree { 527 | public func forEach(_ body: (Element) -> Void) { 528 | root.forEach(body) 529 | } 530 | } 531 | 532 | extension BTreeNode { 533 | func forEach(_ body: (Element) -> Void) { 534 | for i in 0 ..< elementCount { 535 | children?[i].forEach(body) 536 | body(elements[i]) 537 | } 538 | children?[elementCount].forEach(body) 539 | } 540 | } 541 | 542 | extension BTree { 543 | public func contains(_ element: Element) -> Bool { 544 | return root.contains(element) 545 | } 546 | } 547 | 548 | extension BTreeNode { 549 | func contains(_ element: Element) -> Bool { 550 | let slot = self.slot(of: element) 551 | if slot.match { return true } 552 | return children?[slot.index].contains(element) ?? false 553 | } 554 | } 555 | 556 | extension BTreeNode { 557 | var maxElements: Int { return order - 1 } 558 | var minElements: Int { return (order - 1) / 2 } 559 | var maxChildren: Int { return order } 560 | var minChildren: Int { return (order + 1) / 2 } 561 | 562 | var isLeaf: Bool { return children == nil } 563 | var isTooLarge: Bool { return elementCount > maxElements } 564 | } 565 | 566 | extension BTree { 567 | mutating func makeRootUnique() -> Node { 568 | if isKnownUniquelyReferenced(&root) { return root } 569 | root = root.clone() 570 | return root 571 | } 572 | } 573 | 574 | extension BTreeNode { 575 | func clone() -> BTreeNode { 576 | let clone = BTreeNode(order: order, leaf: self.isLeaf) 577 | clone.elements.initialize( 578 | from: self.elements, count: self.elementCount) 579 | if let children = children { 580 | clone.children!.initialize( 581 | from: children, count: self.elementCount + 1) 582 | } 583 | clone.elementCount = self.elementCount 584 | return clone 585 | } 586 | 587 | func makeChildUnique(_ slot: Int) -> BTreeNode { 588 | guard !isKnownUniquelyReferenced(&children![slot]) else { 589 | return children![slot] 590 | } 591 | let clone = children![slot].clone() 592 | children![slot] = clone 593 | return clone 594 | } 595 | } 596 | 597 | extension BTreeNode { 598 | internal func slot(of element: Element) -> (match: Bool, index: Int) { 599 | var start = 0 600 | var end = elementCount 601 | while start < end { 602 | let mid = start + (end - start) / 2 603 | if elements[mid] < element { 604 | start = mid + 1 605 | } 606 | else { 607 | end = mid 608 | } 609 | } 610 | let match = start < elementCount && elements[start] == element 611 | return (match, start) 612 | } 613 | } 614 | 615 | internal struct BTreeSplinter { 616 | let separator: Element 617 | let node: BTreeNode 618 | } 619 | 620 | extension BTreeNode { 621 | typealias Splinter = BTreeSplinter 622 | 623 | func split() -> Splinter { 624 | let count = elementCount 625 | let median = count / 2 626 | let node = BTreeNode(order: order, leaf: self.isLeaf) 627 | let separator = (elements + median).move() 628 | let c = count - median - 1 629 | node.elements.moveInitialize( 630 | from: self.elements + median + 1, count: c) 631 | if self.children != nil { 632 | node.children!.moveInitialize( 633 | from: self.children! + median + 1, count: c + 1) 634 | } 635 | self.elementCount = median 636 | node.elementCount = c 637 | return Splinter(separator: separator, node: node) 638 | } 639 | } 640 | 641 | extension BTreeNode { 642 | func _insertElement(_ element: Element, at index: Int) { 643 | assert(index >= 0 && index <= elementCount) 644 | (elements + index + 1).moveInitialize( 645 | from: elements + index, count: elementCount - index) 646 | (elements + index).initialize(to: element) 647 | elementCount += 1 648 | } 649 | 650 | func _insertChild(_ child: BTreeNode, at index: Int) { 651 | assert(index >= 0 && index <= elementCount + 1) 652 | (children! + index + 1).moveInitialize( 653 | from: children! + index, count: elementCount + 1 - index) 654 | (children! + index).initialize(to: child) 655 | } 656 | 657 | func insert(_ element: Element) -> Splinter? { 658 | let slot = self.slot(of: element) 659 | if slot.match { 660 | return nil // The element is already in the tree. 661 | } 662 | if self.isLeaf { 663 | _insertElement(element, at: slot.index) 664 | return self.isTooLarge ? self.split() : nil 665 | } 666 | let splinter = makeChildUnique(slot.index).insert(element) 667 | guard let s = splinter else { return nil } 668 | _insertElement(s.separator, at: slot.index) 669 | _insertChild(s.node, at: slot.index + 1) 670 | return self.isTooLarge ? self.split() : nil 671 | } 672 | } 673 | 674 | extension BTree { 675 | public mutating func insert(_ element: Element) { 676 | let root = makeRootUnique() 677 | if let splinter = root.insert(element) { 678 | let oldRoot = root 679 | self.root = Node(order: root.order, leaf: false) 680 | self.root.elements.initialize(to: splinter.separator) 681 | self.root.children!.initialize(to: oldRoot) 682 | (self.root.children! + 1).initialize(to: splinter.node) 683 | self.root.elementCount = 1 684 | } 685 | } 686 | } 687 | 688 | 689 | do { 690 | var set = BTree(order: 4) 691 | set.insert(9) 692 | set.insert(6) 693 | set.insert(12) 694 | set.insert(2) 695 | set.insert(10) 696 | set.insert(3) 697 | set.insert(1) 698 | set.insert(13) 699 | set.insert(8) 700 | set.insert(5) 701 | set.insert(11) 702 | set.insert(7) 703 | set.insert(4) 704 | set.forEach { print($0) } 705 | } 706 | -------------------------------------------------------------------------------- /Images/Title Slide.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objcio/OptimizingCollections/a44dc3bf0770aa6ade11127ae466e8fa60e7af76/Images/Title Slide.jpeg -------------------------------------------------------------------------------- /Images/cover@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objcio/OptimizingCollections/a44dc3bf0770aa6ade11127ae466e8fa60e7af76/Images/cover@2x.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Károly Lőrentey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | let package = Package(name: "OptimizingCollections", dependencies: []) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Optimizing Collections in Swift 2 | 3 | [![Book Cover](Images/cover@2x.png)][booklink] 4 | 5 | This repository contains the sample code from the book [Optimizing Collections][booklink]. 6 | 7 | In this book, we show how to write very efficient Swift collection code. Throughout the book, we benchmark everything — with some surprising results. We implement custom data structures with value semantics and copy-on-write behavior such as sorted arrays, binary trees, red-black trees, and B-trees. 8 | 9 | Even if you never implement your own collections, this book helps you reason about the performance of Swift code. 10 | 11 | ## The Code 12 | 13 | This repository includes the full source code of every algorithm discussed in the book: 14 | 15 | 1. [`MyOrderedSet`](./Sources/NSOrderedSet.swift): A rudimentary Swift wrapper for the `NSOrderedSet` class in Foundation. 16 | 2. [`SortedArray`](./Sources/SortedArray.swift): A simple collection storing elements in a sorted array, with O(n) insertions. 17 | 3. [`AlgebraicTree`](./Sources/AlgebraicTree.swift): A purely functional implementation of [red-black trees][rbt] using algebraic data types. 18 | 4. [`COWTree`](./Sources/COWTree.swift): 19 | A procedural, structs-and-classes variant of red-black trees that implements the [copy-on-write optimization][cow]. 20 | 5. [`BTree`](./Sources/BTree.swift): 21 | An implementation of in-memory [B-trees][btree-wiki], based on my [`BTree` package][btree]. 22 | 23 | [rbt]: https://en.wikipedia.org/wiki/Red–black_tree 24 | [cow]: https://en.wikipedia.org/wiki/Copy-on-write 25 | [btree-wiki]: https://en.wikipedia.org/wiki/B-tree 26 | [btree]: https://github.com/lorentey/BTree 27 | 28 | As a bonus, all five data structures implement `BidirectionalCollection`, and 29 | they all have full value semantics. 30 | 31 | Note that while this repository contains nice illustrations of various coding 32 | techniques, I don't recommend you use any of this code in your own projects. I 33 | had to cut some corners to make sure the code remains relatively easy to 34 | understand; full implementations would include lot more functionality that 35 | would just obfuscate my point here. For example, none of these collections 36 | implement support for removing elements, or in fact any of method in 37 | `SetAlgebra` other than `contains` and `insert`. 38 | 39 | For production-ready implementations of ordered collections, please 40 | check out my [BTree package][btree] instead. 41 | 42 | ## The Video 43 | 44 | You can watch the video of my talk at dotSwift 2017 about optimizing collections by clicking on the image below. 45 | 46 | [![dotSwift 2017 - Optimizing Swift Collections](https://img.youtube.com/vi/UdZP6JeTCkM/0.jpg)](https://www.youtube.com/watch?v=UdZP6JeTCkM) 47 | 48 | My slides are available on [Speaker Deck][speakerdeck]. 49 | 50 | [speakerdeck]: https://speakerdeck.com/lorentey/optimizing-swift-collections 51 | 52 | ## The App 53 | 54 | The custom microbenchmarking app I wrote to generate my charts is called 55 | [Attabench], and it is available in a [separate repository][Attabench]. The 56 | insertion benchmark I demonstrated is included in the app by default, so you 57 | can easily reproduce my results on your own computer. 58 | 59 | [![Attabench screenshot](Images/Attabench-screenshot.png)][Attabench] 60 | 61 | [Attabench]: https://github.com/lorentey/Attabench 62 | 63 | Tip: try implementing 64 | your own optimization ideas, and race them with my code! I'm sure you'll easily 65 | beat me if you try. 66 | 67 | 68 | [booklink]: https://www.objc.io/books/optimizing-collections 69 | -------------------------------------------------------------------------------- /Sources/BTree.swift: -------------------------------------------------------------------------------- 1 | public struct BTree { 2 | fileprivate var root: Node 3 | 4 | init(order: Int) { 5 | self.root = Node(order: order) 6 | } 7 | } 8 | 9 | extension BTree { 10 | final class Node { 11 | let order: Int 12 | var mutationCount: Int64 = 0 13 | var elements: [Element] = [] 14 | var children: [Node] = [] 15 | 16 | init(order: Int) { 17 | self.order = order 18 | } 19 | } 20 | } 21 | 22 | #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) 23 | import Darwin 24 | #elseif os(Linux) 25 | import Glibc 26 | #endif 27 | 28 | let cacheSize: Int? = { 29 | #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) 30 | var result: Int = 0 31 | var size = MemoryLayout.size 32 | let status = sysctlbyname("hw.l1dcachesize", &result, &size, nil, 0) 33 | guard status != -1 else { return nil } 34 | return result 35 | #elseif os(Linux) 36 | let result = sysconf(Int32(_SC_LEVEL1_DCACHE_SIZE)) 37 | guard result != -1 else { return nil } 38 | return result 39 | #else 40 | return nil // Unknown platform 41 | #endif 42 | }() 43 | 44 | extension BTree { 45 | public init() { 46 | let order = (cacheSize ?? 32768) / (4 * MemoryLayout.stride) 47 | self.init(order: Swift.max(16, order)) 48 | } 49 | } 50 | 51 | extension BTree { 52 | public func forEach(_ body: (Element) throws -> Void) rethrows { 53 | try root.forEach(body) 54 | } 55 | } 56 | 57 | extension BTree.Node { 58 | func forEach(_ body: (Element) throws -> Void) rethrows { 59 | if children.isEmpty { 60 | try elements.forEach(body) 61 | } 62 | else { 63 | for i in 0 ..< elements.count { 64 | try children[i].forEach(body) 65 | try body(elements[i]) 66 | } 67 | try children[elements.count].forEach(body) 68 | } 69 | } 70 | } 71 | 72 | extension BTree.Node { 73 | internal func slot(of element: Element) -> (match: Bool, index: Int) { 74 | var start = 0 75 | var end = elements.count 76 | while start < end { 77 | let mid = start + (end - start) / 2 78 | if elements[mid] < element { 79 | start = mid + 1 80 | } 81 | else { 82 | end = mid 83 | } 84 | } 85 | let match = start < elements.count && elements[start] == element 86 | return (match, start) 87 | } 88 | } 89 | 90 | extension BTree { 91 | public func contains(_ element: Element) -> Bool { 92 | return root.contains(element) 93 | } 94 | } 95 | 96 | extension BTree.Node { 97 | func contains(_ element: Element) -> Bool { 98 | let slot = self.slot(of: element) 99 | if slot.match { return true } 100 | guard !children.isEmpty else { return false } 101 | return children[slot.index].contains(element) 102 | } 103 | } 104 | 105 | extension BTree { 106 | fileprivate mutating func makeRootUnique() -> Node { 107 | if isKnownUniquelyReferenced(&root) { return root } 108 | root = root.clone() 109 | return root 110 | } 111 | } 112 | 113 | extension BTree.Node { 114 | func clone() -> BTree.Node { 115 | let clone = BTree.Node(order: order) 116 | clone.elements = self.elements 117 | clone.children = self.children 118 | return clone 119 | } 120 | } 121 | 122 | extension BTree.Node { 123 | func makeChildUnique(at slot: Int) -> BTree.Node { 124 | guard !isKnownUniquelyReferenced(&children[slot]) else { 125 | return children[slot] 126 | } 127 | let clone = children[slot].clone() 128 | children[slot] = clone 129 | return clone 130 | } 131 | } 132 | 133 | extension BTree.Node { 134 | var isLeaf: Bool { return children.isEmpty } 135 | var isTooLarge: Bool { return elements.count >= order } 136 | } 137 | 138 | extension BTree { 139 | struct Splinter { 140 | let separator: Element 141 | let node: Node 142 | } 143 | } 144 | 145 | extension BTree.Node { 146 | func split() -> BTree.Splinter { 147 | let count = self.elements.count 148 | let middle = count / 2 149 | 150 | let separator = self.elements[middle] 151 | 152 | let node = BTree.Node(order: order) 153 | node.elements.append(contentsOf: self.elements[middle + 1 ..< count]) 154 | self.elements.removeSubrange(middle ..< count) 155 | 156 | if !isLeaf { 157 | node.children.append(contentsOf: self.children[middle + 1 ..< count + 1]) 158 | self.children.removeSubrange(middle + 1 ..< count + 1) 159 | } 160 | return .init(separator: separator, node: node) 161 | } 162 | } 163 | 164 | extension BTree.Node { 165 | func insert(_ element: Element) -> (old: Element?, splinter: BTree.Splinter?) { 166 | 167 | let slot = self.slot(of: element) 168 | if slot.match { 169 | // The element is already in the tree. 170 | return (self.elements[slot.index], nil) 171 | } 172 | 173 | mutationCount += 1 174 | 175 | if self.isLeaf { 176 | elements.insert(element, at: slot.index) 177 | return (nil, self.isTooLarge ? self.split() : nil) 178 | } 179 | 180 | let (old, splinter) = makeChildUnique(at: slot.index).insert(element) 181 | guard let s = splinter else { return (old, nil) } 182 | elements.insert(s.separator, at: slot.index) 183 | children.insert(s.node, at: slot.index + 1) 184 | return (nil, self.isTooLarge ? self.split() : nil) 185 | } 186 | } 187 | 188 | extension BTree { 189 | @discardableResult 190 | public mutating func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) { 191 | let root = makeRootUnique() 192 | let (old, splinter) = root.insert(element) 193 | if let splinter = splinter { 194 | let r = Node(order: root.order) 195 | r.elements = [splinter.separator] 196 | r.children = [root, splinter.node] 197 | self.root = r 198 | } 199 | return (old == nil, old ?? element) 200 | } 201 | } 202 | 203 | extension BTree { 204 | struct UnsafePathElement { 205 | unowned(unsafe) let node: Node 206 | var slot: Int 207 | 208 | init(_ node: Node, _ slot: Int) { 209 | self.node = node 210 | self.slot = slot 211 | } 212 | } 213 | } 214 | 215 | extension BTree.UnsafePathElement { 216 | var value: Element? { 217 | guard slot < node.elements.count else { return nil } 218 | return node.elements[slot] 219 | } 220 | var child: BTree.Node { 221 | return node.children[slot] 222 | } 223 | var isLeaf: Bool { return node.isLeaf } 224 | var isAtEnd: Bool { return slot == node.elements.count } 225 | } 226 | 227 | extension BTree.UnsafePathElement: Equatable { 228 | static func ==(left: BTree.UnsafePathElement, right: BTree.UnsafePathElement) -> Bool { 229 | return left.node === right.node && left.slot == right.slot 230 | } 231 | } 232 | 233 | extension BTree { 234 | public struct Index { 235 | fileprivate weak var root: Node? 236 | fileprivate let mutationCount: Int64 237 | 238 | fileprivate var path: [UnsafePathElement] 239 | fileprivate var current: UnsafePathElement 240 | 241 | init(startOf tree: BTree) { 242 | self.root = tree.root 243 | self.mutationCount = tree.root.mutationCount 244 | self.path = [] 245 | self.current = UnsafePathElement(tree.root, 0) 246 | while !current.isLeaf { push(0) } 247 | } 248 | 249 | init(endOf tree: BTree) { 250 | self.root = tree.root 251 | self.mutationCount = tree.root.mutationCount 252 | self.path = [] 253 | self.current = UnsafePathElement(tree.root, tree.root.elements.count) 254 | } 255 | } 256 | } 257 | 258 | extension BTree.Index { 259 | fileprivate func validate(for root: BTree.Node) { 260 | precondition(self.root === root) 261 | precondition(self.mutationCount == root.mutationCount) 262 | } 263 | 264 | fileprivate static func validate(_ left: BTree.Index, _ right: BTree.Index) { 265 | precondition(left.root === right.root) 266 | precondition(left.mutationCount == right.mutationCount) 267 | precondition(left.root != nil) 268 | precondition(left.mutationCount == left.root!.mutationCount) 269 | } 270 | } 271 | 272 | extension BTree.Index { 273 | fileprivate mutating func push(_ slot: Int) { 274 | path.append(current) 275 | let child = current.node.children[current.slot] 276 | current = BTree.UnsafePathElement(child, slot) 277 | } 278 | 279 | fileprivate mutating func pop() { 280 | current = self.path.removeLast() 281 | } 282 | } 283 | 284 | extension BTree.Index { 285 | fileprivate mutating func formSuccessor() { 286 | precondition(!current.isAtEnd, "Cannot advance beyond endIndex") 287 | current.slot += 1 288 | if current.isLeaf { 289 | // This loop will rarely execute even once. 290 | while current.isAtEnd, current.node !== root { 291 | // Ascend to the nearest ancestor that has further elements. 292 | pop() 293 | } 294 | } 295 | else { 296 | // Descend to the start of the leftmost leaf node under us. 297 | while !current.isLeaf { 298 | push(0) 299 | } 300 | } 301 | } 302 | } 303 | 304 | extension BTree.Index { 305 | fileprivate mutating func formPredecessor() { 306 | if current.isLeaf { 307 | while current.slot == 0, current.node !== root { 308 | pop() 309 | } 310 | precondition(current.slot > 0, "Cannot go below startIndex") 311 | current.slot -= 1 312 | } 313 | else { 314 | while !current.isLeaf { 315 | let c = current.child 316 | push(c.isLeaf ? c.elements.count - 1 : c.elements.count) 317 | } 318 | } 319 | } 320 | } 321 | 322 | extension BTree.Index: Comparable { 323 | public static func ==(left: BTree.Index, right: BTree.Index) -> Bool { 324 | BTree.Index.validate(left, right) 325 | return left.current == right.current 326 | } 327 | 328 | public static func <(left: BTree.Index, right: BTree.Index) -> Bool { 329 | BTree.Index.validate(left, right) 330 | switch (left.current.value, right.current.value) { 331 | case let (a?, b?): return a < b 332 | case (nil, _): return false 333 | default: return true 334 | } 335 | } 336 | } 337 | 338 | extension BTree: SortedSet { 339 | public var startIndex: Index { return Index(startOf: self) } 340 | public var endIndex: Index { return Index(endOf: self) } 341 | 342 | public subscript(index: Index) -> Element { 343 | index.validate(for: root) 344 | return index.current.value! 345 | } 346 | 347 | public func formIndex(after i: inout Index) { 348 | i.validate(for: root) 349 | i.formSuccessor() 350 | } 351 | 352 | public func formIndex(before i: inout Index) { 353 | i.validate(for: root) 354 | i.formPredecessor() 355 | } 356 | 357 | public func index(after i: Index) -> Index { 358 | i.validate(for: root) 359 | var i = i 360 | i.formSuccessor() 361 | return i 362 | } 363 | 364 | public func index(before i: Index) -> Index { 365 | i.validate(for: root) 366 | var i = i 367 | i.formPredecessor() 368 | return i 369 | } 370 | } 371 | 372 | extension BTree { 373 | public var count: Int { 374 | return root.count 375 | } 376 | } 377 | 378 | extension BTree.Node { 379 | var count: Int { 380 | return children.reduce(elements.count) { $0 + $1.count } 381 | } 382 | } 383 | 384 | extension BTree { 385 | public struct Iterator: IteratorProtocol { 386 | let tree: BTree 387 | var index: Index 388 | 389 | init(_ tree: BTree) { 390 | self.tree = tree 391 | self.index = tree.startIndex 392 | } 393 | 394 | public mutating func next() -> Element? { 395 | guard let result = index.current.value else { return nil } 396 | index.formSuccessor() 397 | return result 398 | } 399 | } 400 | 401 | public func makeIterator() -> Iterator { 402 | return Iterator(self) 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /Sources/BTree2.swift: -------------------------------------------------------------------------------- 1 | public struct BTree2 { 2 | fileprivate var root: Node 3 | 4 | public init(order: Int) { 5 | self.root = Node(order: order) 6 | } 7 | } 8 | 9 | extension BTree2 { 10 | public init() { 11 | let order = (cacheSize ?? 32768) / (4 * MemoryLayout.stride) 12 | self.init(order: Swift.max(16, order)) 13 | } 14 | } 15 | 16 | extension BTree2 { 17 | class Node { 18 | let order: Int 19 | var mutationCount: Int64 = 0 20 | var elementCount: Int = 0 21 | let elements: UnsafeMutablePointer 22 | var children: ContiguousArray = [] 23 | 24 | init(order: Int) { 25 | self.order = order 26 | self.elements = .allocate(capacity: order) 27 | } 28 | 29 | deinit { 30 | elements.deinitialize(count: elementCount) 31 | elements.deallocate(capacity: order) 32 | } 33 | } 34 | } 35 | 36 | extension BTree2 { 37 | public func forEach(_ body: (Element) throws -> Void) rethrows { 38 | try root.forEach(body) 39 | } 40 | } 41 | 42 | extension BTree2.Node { 43 | func forEach(_ body: (Element) throws -> Void) rethrows { 44 | if isLeaf { 45 | for i in 0 ..< elementCount { 46 | try body(elements[i]) 47 | } 48 | } 49 | else { 50 | for i in 0 ..< elementCount { 51 | try children[i].forEach(body) 52 | try body(elements[i]) 53 | } 54 | try children[elementCount].forEach(body) 55 | } 56 | } 57 | } 58 | 59 | extension BTree2.Node { 60 | internal func slot(of element: Element) -> (match: Bool, index: Int) { 61 | var start = 0 62 | var end = elementCount 63 | while start < end { 64 | let mid = start + (end - start) / 2 65 | if elements[mid] < element { 66 | start = mid + 1 67 | } 68 | else { 69 | end = mid 70 | } 71 | } 72 | let match = start < elementCount && elements[start] == element 73 | return (match, start) 74 | } 75 | } 76 | 77 | extension BTree2 { 78 | public func contains(_ element: Element) -> Bool { 79 | return root.contains(element) 80 | } 81 | } 82 | 83 | extension BTree2.Node { 84 | func contains(_ element: Element) -> Bool { 85 | let slot = self.slot(of: element) 86 | if slot.match { return true } 87 | guard !children.isEmpty else { return false } 88 | return children[slot.index].contains(element) 89 | } 90 | } 91 | 92 | extension BTree2 { 93 | fileprivate mutating func makeRootUnique() -> Node { 94 | if isKnownUniquelyReferenced(&root) { return root } 95 | root = root.clone() 96 | return root 97 | } 98 | } 99 | 100 | extension BTree2.Node { 101 | func clone() -> BTree2.Node { 102 | let node = BTree2.Node(order: order) 103 | node.elementCount = self.elementCount 104 | node.elements.initialize(from: self.elements, count: self.elementCount) 105 | if !isLeaf { 106 | node.children.reserveCapacity(order + 1) 107 | node.children += self.children 108 | } 109 | return node 110 | } 111 | } 112 | 113 | extension BTree2.Node { 114 | func makeChildUnique(at slot: Int) -> BTree2.Node { 115 | guard !isKnownUniquelyReferenced(&children[slot]) else { 116 | return children[slot] 117 | } 118 | let clone = children[slot].clone() 119 | children[slot] = clone 120 | return clone 121 | } 122 | } 123 | 124 | extension BTree2.Node { 125 | var maxChildren: Int { return order } 126 | var minChildren: Int { return (maxChildren + 1) / 2 } 127 | var maxElements: Int { return maxChildren - 1 } 128 | var minElements: Int { return minChildren - 1 } 129 | 130 | var isLeaf: Bool { return children.isEmpty } 131 | var isTooLarge: Bool { return elementCount > maxElements } 132 | } 133 | 134 | extension BTree2 { 135 | struct Splinter { 136 | let separator: Element 137 | let node: Node 138 | } 139 | } 140 | 141 | extension BTree2.Node { 142 | func split() -> BTree2.Splinter { 143 | let count = self.elementCount 144 | let middle = count / 2 145 | 146 | let separator = elements[middle] 147 | let node = BTree2.Node(order: self.order) 148 | 149 | let c = count - middle - 1 150 | node.elements.moveInitialize(from: self.elements + middle + 1, count: c) 151 | node.elementCount = c 152 | self.elementCount = middle 153 | 154 | if !isLeaf { 155 | node.children.reserveCapacity(self.order + 1) 156 | node.children += self.children[middle + 1 ... count] 157 | self.children.removeSubrange(middle + 1 ... count) 158 | } 159 | return .init(separator: separator, node: node) 160 | } 161 | } 162 | 163 | extension BTree2.Node { 164 | fileprivate func _insertElement(_ element: Element, at slot: Int) { 165 | assert(slot >= 0 && slot <= elementCount) 166 | (elements + slot + 1).moveInitialize(from: elements + slot, count: elementCount - slot) 167 | (elements + slot).initialize(to: element) 168 | elementCount += 1 169 | } 170 | } 171 | 172 | extension BTree2.Node { 173 | func insert(_ element: Element) -> (old: Element?, splinter: BTree2.Splinter?) { 174 | let slot = self.slot(of: element) 175 | if slot.match { 176 | // The element is already in the tree. 177 | return (self.elements[slot.index], nil) 178 | } 179 | mutationCount += 1 180 | if self.isLeaf { 181 | _insertElement(element, at: slot.index) 182 | return (nil, self.isTooLarge ? self.split() : nil) 183 | } 184 | let (old, splinter) = makeChildUnique(at: slot.index).insert(element) 185 | guard let s = splinter else { return (old, nil) } 186 | _insertElement(s.separator, at: slot.index) 187 | self.children.insert(s.node, at: slot.index + 1) 188 | return (old, self.isTooLarge ? self.split() : nil) 189 | } 190 | } 191 | 192 | extension BTree2 { 193 | @discardableResult 194 | public mutating func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) { 195 | let root = makeRootUnique() 196 | let (old, splinter) = root.insert(element) 197 | if let s = splinter { 198 | let root = BTree2.Node(order: root.order) 199 | root.elementCount = 1 200 | root.elements.initialize(to: s.separator) 201 | root.children = [self.root, s.node] 202 | self.root = root 203 | } 204 | return (inserted: old == nil, memberAfterInsert: old ?? element) 205 | } 206 | } 207 | 208 | extension BTree2 { 209 | struct UnsafePathElement: Equatable { 210 | unowned(unsafe) let node: Node 211 | var slot: Int 212 | 213 | init(_ node: Node, _ slot: Int) { 214 | self.node = node 215 | self.slot = slot 216 | } 217 | 218 | var isLeaf: Bool { return node.isLeaf } 219 | var isAtEnd: Bool { return slot == node.elementCount } 220 | var value: Element? { 221 | guard slot < node.elementCount else { return nil } 222 | return node.elements[slot] 223 | } 224 | var child: Node { 225 | return node.children[slot] 226 | } 227 | 228 | static func ==(left: UnsafePathElement, right: UnsafePathElement) -> Bool { 229 | return left.node === right.node && left.slot == right.slot 230 | } 231 | } 232 | } 233 | 234 | extension BTree2 { 235 | public struct Index: Comparable { 236 | fileprivate weak var root: Node? 237 | fileprivate let mutationCount: Int64 238 | 239 | fileprivate var path: [UnsafePathElement] 240 | fileprivate var current: UnsafePathElement 241 | 242 | init(startOf tree: BTree2) { 243 | self.root = tree.root 244 | self.mutationCount = tree.root.mutationCount 245 | self.path = [] 246 | self.current = UnsafePathElement(tree.root, 0) 247 | while !current.isLeaf { push(0) } 248 | } 249 | 250 | init(endOf tree: BTree2) { 251 | self.root = tree.root 252 | self.mutationCount = tree.root.mutationCount 253 | self.path = [] 254 | self.current = UnsafePathElement(tree.root, tree.root.elementCount) 255 | } 256 | } 257 | } 258 | 259 | extension BTree2.Index { 260 | fileprivate func validate(for root: BTree2.Node) { 261 | precondition(self.root === root) 262 | precondition(self.mutationCount == root.mutationCount) 263 | } 264 | 265 | fileprivate static func validate(_ left: BTree2.Index, _ right: BTree2.Index) { 266 | precondition(left.root === right.root) 267 | precondition(left.mutationCount == right.mutationCount) 268 | precondition(left.root != nil) 269 | precondition(left.mutationCount == left.root!.mutationCount) 270 | } 271 | } 272 | 273 | extension BTree2.Index { 274 | fileprivate mutating func push(_ slot: Int) { 275 | path.append(current) 276 | let child = current.node.children[current.slot] 277 | current = BTree2.UnsafePathElement(child, slot) 278 | } 279 | 280 | fileprivate mutating func pop() { 281 | current = self.path.removeLast() 282 | } 283 | } 284 | 285 | extension BTree2.Index { 286 | fileprivate mutating func formSuccessor() { 287 | precondition(!current.isAtEnd, "Cannot advance beyond endIndex") 288 | current.slot += 1 289 | if current.isLeaf { 290 | while current.isAtEnd, current.node !== root { 291 | pop() 292 | } 293 | } 294 | else { 295 | while !current.isLeaf { 296 | push(0) 297 | } 298 | } 299 | } 300 | } 301 | 302 | extension BTree2.Index { 303 | fileprivate mutating func formPredecessor() { 304 | if current.isLeaf { 305 | while current.slot == 0, current.node !== root { 306 | pop() 307 | } 308 | precondition(current.slot > 0, "Cannot go below startIndex") 309 | current.slot -= 1 310 | } 311 | else { 312 | while !current.isLeaf { 313 | let c = current.child 314 | push(c.isLeaf ? c.elementCount - 1 : c.elementCount) 315 | } 316 | } 317 | } 318 | } 319 | 320 | extension BTree2.Index { 321 | public static func ==(left: BTree2.Index, right: BTree2.Index) -> Bool { 322 | BTree2.Index.validate(left, right) 323 | return left.current == right.current 324 | } 325 | 326 | public static func <(left: BTree2.Index, right: BTree2.Index) -> Bool { 327 | BTree2.Index.validate(left, right) 328 | switch (left.current.value, right.current.value) { 329 | case let (a?, b?): return a < b 330 | case (nil, _): return false 331 | default: return true 332 | } 333 | } 334 | } 335 | 336 | extension BTree2: SortedSet { 337 | public var startIndex: Index { return Index(startOf: self) } 338 | public var endIndex: Index { return Index(endOf: self) } 339 | 340 | public subscript(index: Index) -> Element { 341 | get { 342 | index.validate(for: root) 343 | return index.current.value! 344 | } 345 | } 346 | 347 | public func formIndex(after i: inout Index) { 348 | i.validate(for: root) 349 | i.formSuccessor() 350 | } 351 | 352 | public func index(after i: Index) -> Index { 353 | i.validate(for: root) 354 | var i = i 355 | i.formSuccessor() 356 | return i 357 | } 358 | 359 | public func formIndex(before i: inout Index) { 360 | i.validate(for: root) 361 | i.formPredecessor() 362 | } 363 | 364 | public func index(before i: Index) -> Index { 365 | i.validate(for: root) 366 | var i = i 367 | i.formPredecessor() 368 | return i 369 | } 370 | } 371 | 372 | extension BTree2 { 373 | public var count: Int { 374 | return root.count 375 | } 376 | } 377 | 378 | extension BTree2.Node { 379 | var count: Int { 380 | return children.reduce(elementCount) { $0 + $1.count } 381 | } 382 | } 383 | 384 | extension BTree2 { 385 | public struct Iterator: IteratorProtocol { 386 | let tree: BTree2 387 | var index: Index 388 | 389 | init(_ tree: BTree2) { 390 | self.tree = tree 391 | self.index = tree.startIndex 392 | } 393 | 394 | public mutating func next() -> Element? { 395 | guard let result = index.current.value else { return nil } 396 | index.formSuccessor() 397 | return result 398 | } 399 | } 400 | 401 | public func makeIterator() -> Iterator { 402 | return Iterator(self) 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /Sources/BTree3.swift: -------------------------------------------------------------------------------- 1 | public struct BTree3 { 2 | fileprivate var root: Node 3 | 4 | public init(order: Int) { 5 | self.root = Node(order: order) 6 | } 7 | } 8 | 9 | extension BTree3 { 10 | public init() { 11 | let order = (cacheSize ?? 32768) / (4 * MemoryLayout.stride) 12 | self.init(order: Swift.max(16, order)) 13 | } 14 | } 15 | 16 | extension BTree3 { 17 | class Node { 18 | let order: Int 19 | var mutationCount: Int64 = 0 20 | var elementCount: Int = 0 21 | let elements: UnsafeMutablePointer 22 | var children: ContiguousArray = [] 23 | 24 | init(order: Int) { 25 | self.order = order 26 | self.elements = .allocate(capacity: order) 27 | } 28 | 29 | deinit { 30 | elements.deinitialize(count: elementCount) 31 | elements.deallocate(capacity: order) 32 | } 33 | } 34 | } 35 | 36 | extension BTree3 { 37 | public func forEach(_ body: (Element) throws -> Void) rethrows { 38 | try root.forEach(body) 39 | } 40 | } 41 | 42 | extension BTree3.Node { 43 | func forEach(_ body: (Element) throws -> Void) rethrows { 44 | if isLeaf { 45 | for i in 0 ..< elementCount { 46 | try body(elements[i]) 47 | } 48 | } 49 | else { 50 | for i in 0 ..< elementCount { 51 | try children[i].forEach(body) 52 | try body(elements[i]) 53 | } 54 | try children[elementCount].forEach(body) 55 | } 56 | } 57 | } 58 | 59 | extension BTree3.Node { 60 | internal func slot(of element: Element) -> (match: Bool, index: Int) { 61 | var start = 0 62 | var end = elementCount 63 | while start < end { 64 | let mid = start + (end - start) / 2 65 | if elements[mid] < element { 66 | start = mid + 1 67 | } 68 | else { 69 | end = mid 70 | } 71 | } 72 | let match = start < elementCount && elements[start] == element 73 | return (match, start) 74 | } 75 | } 76 | 77 | extension BTree3 { 78 | public func contains(_ element: Element) -> Bool { 79 | return root.contains(element) 80 | } 81 | } 82 | 83 | extension BTree3.Node { 84 | func contains(_ element: Element) -> Bool { 85 | let slot = self.slot(of: element) 86 | if slot.match { return true } 87 | guard !children.isEmpty else { return false } 88 | return children[slot.index].contains(element) 89 | } 90 | } 91 | 92 | extension BTree3 { 93 | fileprivate mutating func makeRootUnique() -> Node { 94 | if isKnownUniquelyReferenced(&root) { return root } 95 | root = root.clone() 96 | return root 97 | } 98 | } 99 | 100 | extension BTree3.Node { 101 | func clone() -> BTree3.Node { 102 | let node = BTree3.Node(order: order) 103 | node.elementCount = self.elementCount 104 | node.elements.initialize(from: self.elements, count: self.elementCount) 105 | if !isLeaf { 106 | node.children.reserveCapacity(order + 1) 107 | node.children += self.children 108 | } 109 | return node 110 | } 111 | } 112 | 113 | extension BTree3.Node { 114 | func makeChildUnique(at slot: Int) -> BTree3.Node { 115 | guard !isKnownUniquelyReferenced(&children[slot]) else { 116 | return children[slot] 117 | } 118 | let clone = children[slot].clone() 119 | children[slot] = clone 120 | return clone 121 | } 122 | } 123 | 124 | extension BTree3.Node { 125 | var maxChildren: Int { return order } 126 | var minChildren: Int { return (maxChildren + 1) / 2 } 127 | var maxElements: Int { return maxChildren - 1 } 128 | var minElements: Int { return minChildren - 1 } 129 | 130 | var isLeaf: Bool { return children.isEmpty } 131 | var isTooLarge: Bool { return elementCount > maxElements } 132 | } 133 | 134 | extension BTree3 { 135 | struct Splinter { 136 | let separator: Element 137 | let node: Node 138 | } 139 | } 140 | 141 | extension BTree3.Node { 142 | func split() -> BTree3.Splinter { 143 | let count = self.elementCount 144 | let middle = count / 2 145 | 146 | let separator = elements[middle] 147 | let node = BTree3.Node(order: self.order) 148 | 149 | let c = count - middle - 1 150 | node.elements.moveInitialize(from: self.elements + middle + 1, count: c) 151 | node.elementCount = c 152 | self.elementCount = middle 153 | 154 | if !isLeaf { 155 | node.children.reserveCapacity(self.order + 1) 156 | node.children += self.children[middle + 1 ... count] 157 | self.children.removeSubrange(middle + 1 ... count) 158 | } 159 | return .init(separator: separator, node: node) 160 | } 161 | } 162 | 163 | extension BTree3.Node { 164 | fileprivate func _insertElement(_ element: Element, at slot: Int) { 165 | assert(slot >= 0 && slot <= elementCount) 166 | (elements + slot + 1).moveInitialize(from: elements + slot, count: elementCount - slot) 167 | (elements + slot).initialize(to: element) 168 | elementCount += 1 169 | } 170 | } 171 | 172 | extension BTree3.Node { 173 | func insert(_ element: Element) -> (old: Element?, splinter: BTree3.Splinter?) { 174 | let slot = self.slot(of: element) 175 | if slot.match { 176 | // The element is already in the tree. 177 | return (self.elements[slot.index], nil) 178 | } 179 | mutationCount += 1 180 | if self.isLeaf { 181 | _insertElement(element, at: slot.index) 182 | return (nil, self.isTooLarge ? self.split() : nil) 183 | } 184 | let (old, splinter) = makeChildUnique(at: slot.index).insert(element) 185 | guard let s = splinter else { return (old, nil) } 186 | _insertElement(s.separator, at: slot.index) 187 | self.children.insert(s.node, at: slot.index + 1) 188 | return (old, self.isTooLarge ? self.split() : nil) 189 | } 190 | } 191 | 192 | extension BTree3 { 193 | @discardableResult 194 | public mutating func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) { 195 | let root = makeRootUnique() 196 | let (old, splinter) = root.insert(element) 197 | if let s = splinter { 198 | let root = BTree3.Node(order: 16) // <-- 199 | root.elementCount = 1 200 | root.elements.initialize(to: s.separator) 201 | root.children = [self.root, s.node] 202 | self.root = root 203 | } 204 | return (inserted: old == nil, memberAfterInsert: old ?? element) 205 | } 206 | } 207 | 208 | extension BTree3 { 209 | struct UnsafePathElement: Equatable { 210 | unowned(unsafe) let node: Node 211 | var slot: Int 212 | 213 | init(_ node: Node, _ slot: Int) { 214 | self.node = node 215 | self.slot = slot 216 | } 217 | 218 | var isLeaf: Bool { return node.isLeaf } 219 | var isAtEnd: Bool { return slot == node.elementCount } 220 | var value: Element? { 221 | guard slot < node.elementCount else { return nil } 222 | return node.elements[slot] 223 | } 224 | var child: Node { 225 | return node.children[slot] 226 | } 227 | 228 | static func ==(left: UnsafePathElement, right: UnsafePathElement) -> Bool { 229 | return left.node === right.node && left.slot == right.slot 230 | } 231 | } 232 | } 233 | 234 | extension BTree3 { 235 | public struct Index: Comparable { 236 | fileprivate weak var root: Node? 237 | fileprivate let mutationCount: Int64 238 | 239 | fileprivate var path: [UnsafePathElement] 240 | fileprivate var current: UnsafePathElement 241 | 242 | init(startOf tree: BTree3) { 243 | self.root = tree.root 244 | self.mutationCount = tree.root.mutationCount 245 | self.path = [] 246 | self.current = UnsafePathElement(tree.root, 0) 247 | while !current.isLeaf { push(0) } 248 | } 249 | 250 | init(endOf tree: BTree3) { 251 | self.root = tree.root 252 | self.mutationCount = tree.root.mutationCount 253 | self.path = [] 254 | self.current = UnsafePathElement(tree.root, tree.root.elementCount) 255 | } 256 | } 257 | } 258 | 259 | extension BTree3.Index { 260 | fileprivate func validate(for root: BTree3.Node) { 261 | precondition(self.root === root) 262 | precondition(self.mutationCount == root.mutationCount) 263 | } 264 | 265 | fileprivate static func validate(_ left: BTree3.Index, _ right: BTree3.Index) { 266 | precondition(left.root === right.root) 267 | precondition(left.mutationCount == right.mutationCount) 268 | precondition(left.root != nil) 269 | precondition(left.mutationCount == left.root!.mutationCount) 270 | } 271 | } 272 | 273 | extension BTree3.Index { 274 | fileprivate mutating func push(_ slot: Int) { 275 | path.append(current) 276 | let child = current.node.children[current.slot] 277 | current = BTree3.UnsafePathElement(child, slot) 278 | } 279 | 280 | fileprivate mutating func pop() { 281 | current = self.path.removeLast() 282 | } 283 | } 284 | 285 | extension BTree3.Index { 286 | fileprivate mutating func formSuccessor() { 287 | precondition(!current.isAtEnd, "Cannot advance beyond endIndex") 288 | current.slot += 1 289 | if current.isLeaf { 290 | while current.isAtEnd, current.node !== root { 291 | pop() 292 | } 293 | } 294 | else { 295 | while !current.isLeaf { 296 | push(0) 297 | } 298 | } 299 | } 300 | } 301 | 302 | extension BTree3.Index { 303 | fileprivate mutating func formPredecessor() { 304 | if current.isLeaf { 305 | while current.slot == 0, current.node !== root { 306 | pop() 307 | } 308 | precondition(current.slot > 0, "Cannot go below startIndex") 309 | current.slot -= 1 310 | } 311 | else { 312 | while !current.isLeaf { 313 | let c = current.child 314 | push(c.isLeaf ? c.elementCount - 1 : c.elementCount) 315 | } 316 | } 317 | } 318 | } 319 | 320 | extension BTree3.Index { 321 | public static func ==(left: BTree3.Index, right: BTree3.Index) -> Bool { 322 | BTree3.Index.validate(left, right) 323 | return left.current == right.current 324 | } 325 | 326 | public static func <(left: BTree3.Index, right: BTree3.Index) -> Bool { 327 | BTree3.Index.validate(left, right) 328 | switch (left.current.value, right.current.value) { 329 | case let (a?, b?): return a < b 330 | case (nil, _): return false 331 | default: return true 332 | } 333 | } 334 | } 335 | 336 | extension BTree3: SortedSet { 337 | public var startIndex: Index { return Index(startOf: self) } 338 | public var endIndex: Index { return Index(endOf: self) } 339 | 340 | public subscript(index: Index) -> Element { 341 | get { 342 | index.validate(for: root) 343 | return index.current.value! 344 | } 345 | } 346 | 347 | public func formIndex(after i: inout Index) { 348 | i.validate(for: root) 349 | i.formSuccessor() 350 | } 351 | 352 | public func index(after i: Index) -> Index { 353 | i.validate(for: root) 354 | var i = i 355 | i.formSuccessor() 356 | return i 357 | } 358 | 359 | public func formIndex(before i: inout Index) { 360 | i.validate(for: root) 361 | i.formPredecessor() 362 | } 363 | 364 | public func index(before i: Index) -> Index { 365 | i.validate(for: root) 366 | var i = i 367 | i.formPredecessor() 368 | return i 369 | } 370 | } 371 | 372 | extension BTree3 { 373 | public var count: Int { 374 | return root.count 375 | } 376 | } 377 | 378 | extension BTree3.Node { 379 | var count: Int { 380 | return children.reduce(elementCount) { $0 + $1.count } 381 | } 382 | } 383 | 384 | extension BTree3 { 385 | public struct Iterator: IteratorProtocol { 386 | let tree: BTree3 387 | var index: Index 388 | 389 | init(_ tree: BTree3) { 390 | self.tree = tree 391 | self.index = tree.startIndex 392 | } 393 | 394 | public mutating func next() -> Element? { 395 | guard let result = index.current.value else { return nil } 396 | index.formSuccessor() 397 | return result 398 | } 399 | } 400 | 401 | public func makeIterator() -> Iterator { 402 | return Iterator(self) 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /Sources/BTree4.swift: -------------------------------------------------------------------------------- 1 | private let internalOrder = 16 2 | 3 | public struct BTree4 { 4 | fileprivate var root: Node 5 | 6 | public init(order: Int) { 7 | self.root = Node(order: order) 8 | } 9 | } 10 | 11 | extension BTree4 { 12 | public init() { 13 | let order = (cacheSize ?? 32768) / (4 * MemoryLayout.stride) 14 | self.init(order: Swift.max(16, order)) 15 | } 16 | } 17 | 18 | extension BTree4 { 19 | class Node { 20 | let order: Int 21 | var mutationCount: Int64 = 0 22 | var elementCount: Int = 0 23 | let elements: UnsafeMutablePointer 24 | var children: ContiguousArray = [] 25 | 26 | init(order: Int) { 27 | self.order = order 28 | self.elements = .allocate(capacity: order) 29 | } 30 | 31 | deinit { 32 | elements.deinitialize(count: elementCount) 33 | elements.deallocate(capacity: order) 34 | } 35 | } 36 | } 37 | 38 | extension BTree4 { 39 | public func forEach(_ body: (Element) throws -> Void) rethrows { 40 | try root.forEach(body) 41 | } 42 | } 43 | 44 | extension BTree4.Node { 45 | func forEach(_ body: (Element) throws -> Void) rethrows { 46 | if children.isEmpty { 47 | for i in 0 ..< elementCount { 48 | try body(elements[i]) 49 | } 50 | } 51 | else { 52 | for i in 0 ..< elementCount { 53 | try children[i].forEach(body) 54 | try body(elements[i]) 55 | } 56 | try children[elementCount].forEach(body) 57 | } 58 | } 59 | } 60 | 61 | extension BTree4.Node { 62 | internal func slot(of element: Element) -> (match: Bool, index: Int) { 63 | var start = 0 64 | var end = elementCount 65 | while start < end { 66 | let mid = start + (end - start) / 2 67 | if elements[mid] < element { 68 | start = mid + 1 69 | } 70 | else { 71 | end = mid 72 | } 73 | } 74 | let match = start < elementCount && elements[start] == element 75 | return (match, start) 76 | } 77 | } 78 | 79 | extension BTree4 { 80 | public func contains(_ element: Element) -> Bool { 81 | return root.contains(element) 82 | } 83 | } 84 | 85 | extension BTree4.Node { 86 | func contains(_ element: Element) -> Bool { 87 | let slot = self.slot(of: element) 88 | if slot.match { return true } 89 | guard !children.isEmpty else { return false } 90 | return children[slot.index].contains(element) 91 | } 92 | } 93 | 94 | extension BTree4.Node { 95 | func clone() -> BTree4.Node { 96 | let node = BTree4.Node(order: order) 97 | node.elementCount = self.elementCount 98 | node.elements.initialize(from: self.elements, count: self.elementCount) 99 | if !children.isEmpty { 100 | node.children.reserveCapacity(order + 1) 101 | node.children += self.children 102 | } 103 | return node 104 | } 105 | } 106 | 107 | extension BTree4.Node { 108 | var maxChildren: Int { return order } 109 | var minChildren: Int { return (maxChildren + 1) / 2 } 110 | var maxElements: Int { return maxChildren - 1 } 111 | var minElements: Int { return minChildren - 1 } 112 | 113 | var isLeaf: Bool { return children.isEmpty } 114 | var isTooLarge: Bool { return elementCount > maxElements } 115 | } 116 | 117 | extension BTree4 { 118 | struct Splinter { 119 | let separator: Element 120 | let node: Node 121 | } 122 | } 123 | 124 | extension BTree4.Node { 125 | func split() -> BTree4.Splinter { 126 | let count = self.elementCount 127 | let middle = count / 2 128 | 129 | let separator = elements[middle] 130 | let node = BTree4.Node(order: self.order) 131 | 132 | let c = count - middle - 1 133 | node.elements.moveInitialize(from: self.elements + middle + 1, count: c) 134 | node.elementCount = c 135 | self.elementCount = middle 136 | 137 | if !isLeaf { 138 | node.children.reserveCapacity(self.order + 1) 139 | node.children += self.children[middle + 1 ... count] 140 | self.children.removeSubrange(middle + 1 ... count) 141 | } 142 | return .init(separator: separator, node: node) 143 | } 144 | } 145 | 146 | extension UnsafeMutablePointer { 147 | @inline(__always) 148 | fileprivate mutating func advancingInitialize(to value: Pointee, count: Int = 1) { 149 | self.initialize(to: value, count: count) 150 | self += count 151 | } 152 | 153 | @inline(__always) 154 | fileprivate mutating func advancingInitialize(from source: UnsafePointer, count: Int) { 155 | self.initialize(from: source, count: count) 156 | self += count 157 | } 158 | } 159 | 160 | extension BTree4.Node { 161 | fileprivate func _insertElement(_ element: Element, at slot: Int) { 162 | assert(slot >= 0 && slot <= elementCount) 163 | (elements + slot + 1).moveInitialize(from: elements + slot, count: elementCount - slot) 164 | (elements + slot).initialize(to: element) 165 | elementCount += 1 166 | } 167 | } 168 | 169 | 170 | extension BTree4.Node { 171 | func _splittingInsert(_ element: Element, with child: BTree4.Node? = nil, at slot: Int) -> BTree4.Splinter? { 172 | _insertElement(element, at: slot) 173 | if let child = child { 174 | children.insert(child, at: slot + 1) 175 | } 176 | if elementCount <= maxElements { 177 | return nil 178 | } 179 | return split() 180 | } 181 | 182 | func insert(_ element: Element) -> (old: Element?, splinter: BTree4.Splinter?) { 183 | let slot = self.slot(of: element) 184 | if slot.match { 185 | // The element is already in the tree. 186 | return (self.elements[slot.index], nil) 187 | } 188 | mutationCount += 1 189 | if self.isLeaf { 190 | _insertElement(element, at: slot.index) 191 | return (nil, isTooLarge ? split() : nil) 192 | } 193 | 194 | if isKnownUniquelyReferenced(&children[slot.index]) { 195 | let (old, splinter) = children[slot.index].insert(element) 196 | guard let s = splinter else { return (old, nil) } 197 | _insertElement(s.separator, at: slot.index) 198 | children.insert(s.node, at: slot.index + 1) 199 | return (nil, isTooLarge ? split() : nil) 200 | } 201 | 202 | let (old, trunk, splinter) = children[slot.index].inserting(element) 203 | children[slot.index] = trunk 204 | if let s = splinter { 205 | _insertElement(s.separator, at: slot.index) 206 | children.insert(s.node, at: slot.index + 1) 207 | return (nil, isTooLarge ? split() : nil) 208 | } 209 | return (old, nil) 210 | } 211 | } 212 | 213 | extension BTree4.Node { 214 | private func _inserting(_ element: Element, with neighbors: (BTree4.Node, BTree4.Node)? = nil, at slot: Int) -> (trunk: BTree4.Node, splinter: BTree4.Splinter?) { 215 | if elementCount < maxElements { 216 | let trunk = BTree4.Node(order: order) 217 | trunk.elementCount = elementCount + 1 218 | var p = trunk.elements 219 | p.advancingInitialize(from: elements, count: slot) 220 | p.advancingInitialize(to: element) 221 | p.advancingInitialize(from: elements + slot, count: elementCount - slot) 222 | if let neighbors = neighbors { 223 | trunk.children = self.children 224 | trunk.children.insert(neighbors.1, at: slot + 1) 225 | trunk.children[slot] = neighbors.0 226 | } 227 | return (trunk, nil) 228 | } 229 | // Split 230 | let middle = (elementCount + 1) / 2 231 | let separator: Element 232 | let left = BTree4.Node(order: order) 233 | let right = BTree4.Node(order: order) 234 | left.elementCount = middle 235 | right.elementCount = elementCount - middle 236 | if middle < slot { 237 | separator = elements[middle] 238 | 239 | left.elements.initialize(from: elements, count: middle) 240 | 241 | var p = right.elements 242 | p.advancingInitialize(from: elements + middle + 1, count: slot - middle - 1) 243 | p.advancingInitialize(to: element) 244 | p.advancingInitialize(from: elements + slot, count: elementCount - slot) 245 | 246 | if let neighbors = neighbors { 247 | left.children += children[0 ... middle] 248 | right.children += children[middle + 1 ..< slot] 249 | right.children.append(neighbors.0) 250 | right.children.append(neighbors.1) 251 | if slot < elementCount { 252 | right.children += children[slot + 1 ... elementCount] 253 | } 254 | } 255 | } 256 | else if middle > slot { 257 | separator = elements[middle - 1] 258 | 259 | var p = left.elements 260 | p.advancingInitialize(from: elements, count: slot) 261 | p.advancingInitialize(to: element) 262 | p.advancingInitialize(from: elements + slot, count: middle - slot - 1) 263 | 264 | right.elements.initialize(from: elements + middle, count: elementCount - middle) 265 | 266 | if let neighbors = neighbors { 267 | left.children += children[0 ..< slot] 268 | left.children.append(neighbors.0) 269 | left.children.append(neighbors.1) 270 | left.children += children[slot + 1 ..< middle] 271 | right.children += children[middle ... elementCount] 272 | } 273 | } 274 | else { // median == slot 275 | separator = element 276 | 277 | left.elements.initialize(from: elements, count: middle) 278 | right.elements.initialize(from: elements + middle, count: elementCount - middle) 279 | 280 | if let neighbors = neighbors { 281 | left.children += children[0 ..< middle] 282 | left.children.append(neighbors.0) 283 | 284 | right.children.append(neighbors.1) 285 | right.children += children[middle + 1 ... elementCount] 286 | } 287 | } 288 | return (left, BTree4.Splinter(separator: separator, node: right)) 289 | } 290 | 291 | func inserting(_ element: Element) -> (old: Element?, trunk: BTree4.Node, splinter: BTree4.Splinter?) { 292 | let slot = self.slot(of: element) 293 | if slot.match { 294 | // The element is already in the tree. 295 | return (self.elements[slot.index], self, nil) 296 | } 297 | if isLeaf { 298 | let (trunk, splinter) = self._inserting(element, at: slot.index) 299 | return (nil, trunk, splinter) 300 | } 301 | else { 302 | let (old, trunk, splinter) = self.children[slot.index].inserting(element) 303 | if let old = old { return (old, self, nil) } 304 | if let splinter = splinter { 305 | let (t, s) = self._inserting(splinter.separator, with: (trunk, splinter.node), at: slot.index) 306 | return (nil, t, s) 307 | } 308 | else { 309 | let node = self.clone() 310 | node.children[slot.index] = trunk 311 | return (nil, node, nil) 312 | } 313 | } 314 | } 315 | } 316 | 317 | extension BTree4.Node { 318 | convenience init(trunk: BTree4.Node, splinter: BTree4.Splinter) { 319 | self.init(order: internalOrder) 320 | self.elementCount = 1 321 | self.elements.initialize(to: splinter.separator) 322 | self.children = [trunk, splinter.node] 323 | } 324 | } 325 | 326 | extension BTree4 { 327 | @discardableResult 328 | public mutating func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) { 329 | if isKnownUniquelyReferenced(&root) { 330 | let (old, splinter) = root.insert(element) 331 | if let splinter = splinter { 332 | self.root = Node(trunk: self.root, splinter: splinter) 333 | } 334 | return (old == nil, old ?? element) 335 | } 336 | else { 337 | let (old, trunk, splinter) = root.inserting(element) 338 | if let splinter = splinter { 339 | self.root = Node(trunk: trunk, splinter: splinter) 340 | } 341 | else { 342 | self.root = trunk 343 | } 344 | return (old == nil, old ?? element) 345 | } 346 | } 347 | } 348 | 349 | extension BTree4 { 350 | struct UnsafePathElement: Equatable { 351 | unowned(unsafe) let node: Node 352 | var slot: Int 353 | 354 | init(_ node: Node, _ slot: Int) { 355 | self.node = node 356 | self.slot = slot 357 | } 358 | 359 | var isLeaf: Bool { return node.isLeaf } 360 | var isAtEnd: Bool { return slot == node.elementCount } 361 | var value: Element? { 362 | guard slot < node.elementCount else { return nil } 363 | return node.elements[slot] 364 | } 365 | var child: Node { 366 | return node.children[slot] 367 | } 368 | 369 | static func ==(left: UnsafePathElement, right: UnsafePathElement) -> Bool { 370 | return left.node === right.node && left.slot == right.slot 371 | } 372 | } 373 | } 374 | 375 | extension BTree4 { 376 | public struct Index: Comparable { 377 | fileprivate weak var root: Node? 378 | fileprivate let mutationCount: Int64 379 | 380 | fileprivate var path: [UnsafePathElement] 381 | fileprivate var current: UnsafePathElement 382 | 383 | init(startOf tree: BTree4) { 384 | self.root = tree.root 385 | self.mutationCount = tree.root.mutationCount 386 | self.path = [] 387 | self.current = UnsafePathElement(tree.root, 0) 388 | while !current.isLeaf { push(0) } 389 | } 390 | 391 | init(endOf tree: BTree4) { 392 | self.root = tree.root 393 | self.mutationCount = tree.root.mutationCount 394 | self.path = [] 395 | self.current = UnsafePathElement(tree.root, tree.root.elementCount) 396 | } 397 | } 398 | } 399 | 400 | extension BTree4.Index { 401 | fileprivate func validate(for root: BTree4.Node) { 402 | precondition(self.root === root) 403 | precondition(self.mutationCount == root.mutationCount) 404 | } 405 | 406 | fileprivate static func validate(_ left: BTree4.Index, _ right: BTree4.Index) { 407 | precondition(left.root === right.root) 408 | precondition(left.mutationCount == right.mutationCount) 409 | precondition(left.root != nil) 410 | precondition(left.mutationCount == left.root!.mutationCount) 411 | } 412 | } 413 | 414 | extension BTree4.Index { 415 | fileprivate mutating func push(_ slot: Int) { 416 | path.append(current) 417 | let child = current.node.children[current.slot] 418 | current = BTree4.UnsafePathElement(child, slot) 419 | } 420 | 421 | fileprivate mutating func pop() { 422 | current = self.path.removeLast() 423 | } 424 | } 425 | 426 | extension BTree4.Index { 427 | fileprivate mutating func formSuccessor() { 428 | precondition(!current.isAtEnd, "Cannot advance beyond endIndex") 429 | current.slot += 1 430 | if current.isLeaf { 431 | while current.isAtEnd, current.node !== root { 432 | pop() 433 | } 434 | } 435 | else { 436 | while !current.isLeaf { 437 | push(0) 438 | } 439 | } 440 | } 441 | } 442 | 443 | extension BTree4.Index { 444 | fileprivate mutating func formPredecessor() { 445 | if current.isLeaf { 446 | while current.slot == 0, current.node !== root { 447 | pop() 448 | } 449 | precondition(current.slot > 0, "Cannot go below startIndex") 450 | current.slot -= 1 451 | } 452 | else { 453 | while !current.isLeaf { 454 | let c = current.child 455 | push(c.isLeaf ? c.elementCount - 1 : c.elementCount) 456 | } 457 | } 458 | } 459 | } 460 | 461 | extension BTree4.Index { 462 | public static func ==(left: BTree4.Index, right: BTree4.Index) -> Bool { 463 | BTree4.Index.validate(left, right) 464 | return left.current == right.current 465 | } 466 | 467 | public static func <(left: BTree4.Index, right: BTree4.Index) -> Bool { 468 | BTree4.Index.validate(left, right) 469 | switch (left.current.value, right.current.value) { 470 | case let (a?, b?): return a < b 471 | case (nil, _): return false 472 | default: return true 473 | } 474 | } 475 | } 476 | 477 | extension BTree4: SortedSet { 478 | public var startIndex: Index { return Index(startOf: self) } 479 | public var endIndex: Index { return Index(endOf: self) } 480 | 481 | public subscript(index: Index) -> Element { 482 | get { 483 | index.validate(for: root) 484 | return index.current.value! 485 | } 486 | } 487 | 488 | public func formIndex(after i: inout Index) { 489 | i.validate(for: root) 490 | i.formSuccessor() 491 | } 492 | 493 | public func index(after i: Index) -> Index { 494 | i.validate(for: root) 495 | var i = i 496 | i.formSuccessor() 497 | return i 498 | } 499 | 500 | public func formIndex(before i: inout Index) { 501 | i.validate(for: root) 502 | i.formPredecessor() 503 | } 504 | 505 | public func index(before i: Index) -> Index { 506 | i.validate(for: root) 507 | var i = i 508 | i.formPredecessor() 509 | return i 510 | } 511 | } 512 | 513 | extension BTree4 { 514 | public var count: Int { 515 | return root.count 516 | } 517 | } 518 | 519 | extension BTree4.Node { 520 | var count: Int { 521 | return children.reduce(elementCount) { $0 + $1.count } 522 | } 523 | } 524 | 525 | extension BTree4 { 526 | public struct Iterator: IteratorProtocol { 527 | let tree: BTree4 528 | var index: Index 529 | 530 | init(_ tree: BTree4) { 531 | self.tree = tree 532 | self.index = tree.startIndex 533 | } 534 | 535 | public mutating func next() -> Element? { 536 | guard let result = index.current.value else { return nil } 537 | index.formSuccessor() 538 | return result 539 | } 540 | } 541 | 542 | public func makeIterator() -> Iterator { 543 | return Iterator(self) 544 | } 545 | } 546 | 547 | extension BTree4 { 548 | public func validate() { 549 | _ = root.validate(level: 0) 550 | } 551 | } 552 | 553 | extension BTree4.Node { 554 | func validate(level: Int, min: Element? = nil, max: Element? = nil) -> Int { 555 | // Check balance. 556 | precondition(!isTooLarge) 557 | precondition(level == 0 || elementCount >= minElements) 558 | 559 | if elementCount == 0 { 560 | precondition(children.isEmpty) 561 | return 0 562 | } 563 | 564 | // Check element ordering. 565 | var previous = min 566 | for i in 0 ..< elementCount { 567 | let next = elements[i] 568 | precondition(previous == nil || previous! < next) 569 | previous = next 570 | } 571 | 572 | if isLeaf { 573 | return 0 574 | } 575 | 576 | // Check children. 577 | precondition(children.count == elementCount + 1) 578 | let depth = children[0].validate(level: level + 1, min: min, max: elements[0]) 579 | for i in 1 ..< elementCount { 580 | let d = children[i].validate(level: level + 1, min: elements[i - 1], max: elements[i]) 581 | precondition(depth == d) 582 | } 583 | let d = children[elementCount].validate(level: level + 1, min: elements[elementCount - 1], max: max) 584 | precondition(depth == d) 585 | return depth + 1 586 | } 587 | } 588 | -------------------------------------------------------------------------------- /Sources/NSOrderedSet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | private class Canary {} 4 | 5 | public struct OrderedSet: SortedSet { 6 | fileprivate var storage = NSMutableOrderedSet() 7 | fileprivate var canary = Canary() 8 | public init() {} 9 | } 10 | 11 | extension OrderedSet { 12 | public func forEach(_ body: (Element) -> Void) { 13 | storage.forEach { body($0 as! Element) } 14 | } 15 | } 16 | 17 | extension OrderedSet { 18 | fileprivate static func compare(_ a: Any, _ b: Any) -> ComparisonResult 19 | { 20 | let a = a as! Element, b = b as! Element 21 | if a < b { return .orderedAscending } 22 | if a > b { return .orderedDescending } 23 | return .orderedSame 24 | } 25 | } 26 | 27 | extension OrderedSet { 28 | public func index(of element: Element) -> Int? { 29 | let index = storage.index( 30 | of: element, 31 | inSortedRange: NSRange(0 ..< storage.count), 32 | usingComparator: OrderedSet.compare) 33 | return index == NSNotFound ? nil : index 34 | } 35 | } 36 | 37 | extension OrderedSet { 38 | public func contains(_ element: Element) -> Bool { 39 | return index(of: element) != nil 40 | } 41 | } 42 | 43 | extension OrderedSet { 44 | public func contains2(_ element: Element) -> Bool { 45 | return storage.contains(element) || index(of: element) != nil 46 | } 47 | } 48 | 49 | extension OrderedSet: RandomAccessCollection { 50 | public typealias Index = Int 51 | public typealias Indices = CountableRange 52 | 53 | public var startIndex: Int { return 0 } 54 | public var endIndex: Int { return storage.count } 55 | public subscript(i: Int) -> Element { return storage[i] as! Element } 56 | } 57 | 58 | extension OrderedSet { 59 | fileprivate mutating func makeUnique() { 60 | if !isKnownUniquelyReferenced(&canary) { 61 | storage = storage.mutableCopy() as! NSMutableOrderedSet 62 | canary = Canary() 63 | } 64 | } 65 | } 66 | 67 | extension OrderedSet { 68 | fileprivate func index(for value: Element) -> Int { 69 | return storage.index( 70 | of: value, 71 | inSortedRange: NSRange(0 ..< storage.count), 72 | options: .insertionIndex, 73 | usingComparator: OrderedSet.compare) 74 | } 75 | } 76 | 77 | extension OrderedSet { 78 | @discardableResult 79 | public mutating func insert(_ newElement: Element) -> (inserted: Bool, memberAfterInsert: Element) 80 | { 81 | let index = self.index(for: newElement) 82 | if index < storage.count, storage[index] as! Element == newElement { 83 | return (false, storage[index] as! Element) 84 | } 85 | makeUnique() 86 | storage.insert(newElement, at: index) 87 | return (true, newElement) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Sources/Preface.swift: -------------------------------------------------------------------------------- 1 | #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) 2 | import Darwin // for arc4random_uniform() 3 | #elseif os(Linux) 4 | import Glibc // for random() 5 | #endif 6 | 7 | extension Sequence { 8 | public func shuffled() -> [Iterator.Element] { 9 | var contents = Array(self) 10 | for i in 0 ..< contents.count { 11 | #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) 12 | // FIXME: This breaks if the array has 2^32 elements or more. 13 | let j = Int(arc4random_uniform(UInt32(contents.count))) 14 | #elseif os(Linux) 15 | // FIXME: This has modulo bias. Also, `random` should be seeded by calling `srandom`. 16 | let j = random() % contents.count 17 | #endif 18 | if i != j { 19 | swap(&contents[i], &contents[j]) 20 | } 21 | } 22 | return contents 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/RedBlackTree.swift: -------------------------------------------------------------------------------- 1 | public enum Color { 2 | case black 3 | case red 4 | } 5 | 6 | public enum RedBlackTree { 7 | case empty 8 | indirect case node(Color, Element, RedBlackTree, RedBlackTree) 9 | } 10 | 11 | public extension RedBlackTree { 12 | func contains(_ element: Element) -> Bool { 13 | switch self { 14 | case .empty: 15 | return false 16 | case .node(_, element, _, _): 17 | return true 18 | case let .node(_, value, left, _) where value > element: 19 | return left.contains(element) 20 | case let .node(_, _, _, right): 21 | return right.contains(element) 22 | } 23 | } 24 | } 25 | 26 | public extension RedBlackTree { 27 | func forEach(_ body: (Element) throws -> Void) rethrows { 28 | switch self { 29 | case .empty: 30 | break 31 | case let .node(_, value, left, right): 32 | try left.forEach(body) 33 | try body(value) 34 | try right.forEach(body) 35 | } 36 | } 37 | } 38 | 39 | extension Color { 40 | var symbol: String { 41 | switch self { 42 | case .black: return "■" 43 | case .red: return "□" 44 | } 45 | } 46 | } 47 | 48 | extension RedBlackTree: CustomStringConvertible { 49 | func diagram(_ top: String, _ root: String, _ bottom: String) -> String { 50 | switch self { 51 | case .empty: 52 | return root + "•\n" 53 | case let .node(color, value, .empty, .empty): 54 | return root + "\(color.symbol) \(value)\n" 55 | case let .node(color, value, left, right): 56 | return right.diagram(top + " ", top + "┌───", top + "│ ") 57 | + root + "\(color.symbol) \(value)\n" 58 | + left.diagram(bottom + "│ ", bottom + "└───", bottom + " ") 59 | } 60 | } 61 | 62 | public var description: String { 63 | return self.diagram("", "", "") 64 | } 65 | } 66 | 67 | extension RedBlackTree { 68 | @discardableResult 69 | public mutating func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) 70 | { 71 | let (tree, old) = inserting(element) 72 | self = tree 73 | return (old == nil, old ?? element) 74 | } 75 | } 76 | 77 | extension RedBlackTree { 78 | public func inserting(_ element: Element) -> (tree: RedBlackTree, existingMember: Element?) { 79 | let (tree, old) = _inserting(element) 80 | switch tree { 81 | case let .node(.red, value, left, right): 82 | return (.node(.black, value, left, right), old) 83 | default: 84 | return (tree, old) 85 | } 86 | } 87 | } 88 | 89 | extension RedBlackTree { 90 | func _inserting(_ element: Element) -> (tree: RedBlackTree, old: Element?) 91 | { 92 | switch self { 93 | 94 | case .empty: 95 | return (.node(.red, element, .empty, .empty), nil) 96 | 97 | case let .node(_, value, _, _) where value == element: 98 | return (self, value) 99 | 100 | case let .node(color, value, left, right) where value > element: 101 | let (l, old) = left._inserting(element) 102 | if let old = old { return (self, old) } 103 | return (balanced(color, value, l, right), nil) 104 | 105 | case let .node(color, value, left, right): 106 | let (r, old) = right._inserting(element) 107 | if let old = old { return (self, old) } 108 | return (balanced(color, value, left, r), nil) 109 | } 110 | } 111 | } 112 | 113 | extension RedBlackTree { 114 | func balanced(_ color: Color, _ value: Element, _ left: RedBlackTree, _ right: RedBlackTree) -> RedBlackTree { 115 | switch (color, value, left, right) { 116 | case let (.black, z, .node(.red, y, .node(.red, x, a, b), c), d): 117 | return .node(.red, y, .node(.black, x, a, b), .node(.black, z, c, d)) 118 | case let (.black, z, .node(.red, x, a, .node(.red, y, b, c)), d): 119 | return .node(.red, y, .node(.black, x, a, b), .node(.black, z, c, d)) 120 | case let (.black, x, a, .node(.red, z, .node(.red, y, b, c), d)): 121 | return .node(.red, y, .node(.black, x, a, b), .node(.black, z, c, d)) 122 | case let (.black, x, a, .node(.red, y, b, .node(.red, z, c, d))): 123 | return .node(.red, y, .node(.black, x, a, b), .node(.black, z, c, d)) 124 | default: 125 | return .node(color, value, left, right) 126 | } 127 | } 128 | } 129 | 130 | extension RedBlackTree { 131 | public struct Index { 132 | fileprivate var value: Element? 133 | } 134 | } 135 | 136 | extension RedBlackTree.Index: Comparable { 137 | public static func ==(left: RedBlackTree.Index, right: RedBlackTree.Index) -> Bool { 138 | return left.value == right.value 139 | } 140 | 141 | public static func <(left: RedBlackTree.Index, right: RedBlackTree.Index) -> Bool { 142 | if let lv = left.value, let rv = right.value { 143 | return lv < rv 144 | } 145 | return left.value != nil 146 | } 147 | } 148 | 149 | extension RedBlackTree { 150 | func min() -> Element? { 151 | switch self { 152 | case .empty: 153 | return nil 154 | case let .node(_, value, left, _): 155 | return left.min() ?? value 156 | } 157 | } 158 | } 159 | 160 | extension RedBlackTree { 161 | func max() -> Element? { 162 | var node = self 163 | var maximum: Element? = nil 164 | while case let .node(_, value, _, right) = node { 165 | maximum = value 166 | node = right 167 | } 168 | return maximum 169 | } 170 | } 171 | 172 | extension RedBlackTree: Collection { 173 | public var startIndex: Index { return Index(value: self.min()) } 174 | public var endIndex: Index { return Index(value: nil) } 175 | 176 | public subscript(i: Index) -> Element { 177 | return i.value! 178 | } 179 | } 180 | 181 | extension RedBlackTree: BidirectionalCollection { 182 | public func formIndex(after i: inout Index) { 183 | let v = self.value(following: i.value!) 184 | precondition(v.found) 185 | i.value = v.next 186 | } 187 | 188 | public func index(after i: Index) -> Index { 189 | let v = self.value(following: i.value!) 190 | precondition(v.found) 191 | return Index(value: v.next) 192 | } 193 | } 194 | 195 | extension RedBlackTree { 196 | func value(following element: Element) -> (found: Bool, next: Element?) { 197 | switch self { 198 | case .empty: 199 | return (false, nil) 200 | case .node(_, element, _, let right): 201 | return (true, right.min()) 202 | case let .node(_, value, left, _) where value > element: 203 | let v = left.value(following: element) 204 | return (v.found, v.next ?? value) 205 | case let .node(_, _, _, right): 206 | return right.value(following: element) 207 | } 208 | } 209 | } 210 | 211 | extension RedBlackTree { 212 | func value(preceding element: Element) -> (found: Bool, next: Element?) { 213 | var node = self 214 | var previous: Element? = nil 215 | while case let .node(_, value, left, right) = node { 216 | if value > element { 217 | node = left 218 | } 219 | else if value < element { 220 | previous = value 221 | node = right 222 | } 223 | else { 224 | return (true, left.max()) 225 | } 226 | } 227 | return (false, previous) 228 | } 229 | } 230 | 231 | extension RedBlackTree { 232 | public func formIndex(before i: inout Index) { 233 | let v = self.value(preceding: i.value!) 234 | precondition(v.found) 235 | i.value = v.next 236 | } 237 | 238 | public func index(before i: Index) -> Index { 239 | let v = self.value(preceding: i.value!) 240 | precondition(v.found) 241 | return Index(value: v.next) 242 | } 243 | } 244 | 245 | extension RedBlackTree { 246 | public var count: Int { 247 | switch self { 248 | case .empty: 249 | return 0 250 | case let .node(_, _, left, right): 251 | return left.count + 1 + right.count 252 | } 253 | } 254 | } 255 | 256 | extension RedBlackTree: SortedSet { 257 | public init() { 258 | self = .empty 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /Sources/RedBlackTree2.swift: -------------------------------------------------------------------------------- 1 | public struct RedBlackTree2: SortedSet { 2 | fileprivate var root: Node? = nil 3 | 4 | public init() {} 5 | } 6 | 7 | extension RedBlackTree2 { 8 | class Node { 9 | var color: Color 10 | var value: Element 11 | var left: Node? = nil 12 | var right: Node? = nil 13 | var mutationCount: Int64 = 0 14 | 15 | init(_ color: Color, _ value: Element, _ left: Node?, _ right: Node?) { 16 | self.color = color 17 | self.value = value 18 | self.left = left 19 | self.right = right 20 | } 21 | } 22 | } 23 | 24 | extension RedBlackTree2 { 25 | public func forEach(_ body: (Element) throws -> Void) rethrows { 26 | try root?.forEach(body) 27 | } 28 | } 29 | 30 | extension RedBlackTree2.Node { 31 | func forEach(_ body: (Element) throws -> Void) rethrows { 32 | try left?.forEach(body) 33 | try body(value) 34 | try right?.forEach(body) 35 | } 36 | } 37 | 38 | extension RedBlackTree2 { 39 | public func contains(_ element: Element) -> Bool { 40 | var node = root 41 | while let n = node { 42 | if n.value < element { 43 | node = n.right 44 | } 45 | else if n.value > element { 46 | node = n.left 47 | } 48 | else { 49 | return true 50 | } 51 | } 52 | return false 53 | } 54 | } 55 | 56 | private func diagram(for node: RedBlackTree2.Node?, _ top: String = "", _ root: String = "", _ bottom: String = "") -> String { 57 | guard let node = node else { 58 | return root + "•\n" 59 | } 60 | if node.left == nil && node.right == nil { 61 | return root + "\(node.color.symbol) \(node.value)\n" 62 | } 63 | return diagram(for: node.right, top + " ", top + "┌───", top + "│ ") 64 | + root + "\(node.color.symbol) \(node.value)\n" 65 | + diagram(for: node.left, bottom + "│ ", bottom + "└───", bottom + " ") 66 | } 67 | 68 | extension RedBlackTree2: CustomStringConvertible { 69 | public var description: String { 70 | return diagram(for: root) 71 | } 72 | } 73 | 74 | extension RedBlackTree2.Node { 75 | func clone() -> Self { 76 | return .init(color, value, left, right) 77 | } 78 | } 79 | 80 | extension RedBlackTree2 { 81 | fileprivate mutating func makeRootUnique() -> Node? { 82 | if root != nil, !isKnownUniquelyReferenced(&root) { 83 | root = root!.clone() 84 | } 85 | return root 86 | } 87 | } 88 | 89 | extension RedBlackTree2.Node { 90 | func makeLeftUnique() -> RedBlackTree2.Node? { 91 | if left != nil, !isKnownUniquelyReferenced(&left) { 92 | left = left!.clone() 93 | } 94 | return left 95 | } 96 | 97 | func makeRightUnique() -> RedBlackTree2.Node? { 98 | if right != nil, !isKnownUniquelyReferenced(&right) { 99 | right = right!.clone() 100 | } 101 | return right 102 | } 103 | } 104 | 105 | extension RedBlackTree2 { 106 | @discardableResult 107 | public mutating func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) { 108 | guard let root = makeRootUnique() else { 109 | self.root = Node(.black, element, nil, nil) 110 | return (true, element) 111 | } 112 | defer { root.color = .black } 113 | return root.insert(element) 114 | } 115 | } 116 | 117 | extension RedBlackTree2.Node { 118 | func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) { 119 | mutationCount += 1 120 | if element < self.value { 121 | if let next = makeLeftUnique() { 122 | let result = next.insert(element) 123 | if result.inserted { self.balance() } 124 | return result 125 | } 126 | else { 127 | self.left = .init(.red, element, nil, nil) 128 | return (inserted: true, memberAfterInsert: element) 129 | } 130 | } 131 | if element > self.value { 132 | if let next = makeRightUnique() { 133 | let result = next.insert(element) 134 | if result.inserted { self.balance() } 135 | return result 136 | } 137 | else { 138 | self.right = .init(.red, element, nil, nil) 139 | return (inserted: true, memberAfterInsert: element) 140 | } 141 | } 142 | return (inserted: false, memberAfterInsert: self.value) 143 | } 144 | } 145 | 146 | extension RedBlackTree2.Node { 147 | func balance() { 148 | if self.color == .red { return } 149 | if left?.color == .red { 150 | if left?.left?.color == .red { 151 | let l = left! 152 | let ll = l.left! 153 | swap(&self.value, &l.value) 154 | (self.left, l.left, l.right, self.right) = (ll, l.right, self.right, l) 155 | self.color = .red 156 | l.color = .black 157 | ll.color = .black 158 | return 159 | } 160 | if left?.right?.color == .red { 161 | let l = left! 162 | let lr = l.right! 163 | swap(&self.value, &lr.value) 164 | (l.right, lr.left, lr.right, self.right) = (lr.left, lr.right, self.right, lr) 165 | self.color = .red 166 | l.color = .black 167 | lr.color = .black 168 | return 169 | } 170 | } 171 | if right?.color == .red { 172 | if right?.left?.color == .red { 173 | let r = right! 174 | let rl = r.left! 175 | swap(&self.value, &rl.value) 176 | (self.left, rl.left, rl.right, r.left) = (rl, self.left, rl.left, rl.right) 177 | self.color = .red 178 | r.color = .black 179 | rl.color = .black 180 | return 181 | } 182 | if right?.right?.color == .red { 183 | let r = right! 184 | let rr = r.right! 185 | swap(&self.value, &r.value) 186 | (self.left, r.left, r.right, self.right) = (r, self.left, r.left, rr) 187 | self.color = .red 188 | r.color = .black 189 | rr.color = .black 190 | return 191 | } 192 | } 193 | } 194 | } 195 | 196 | private struct Weak { 197 | weak var value: Wrapped? 198 | 199 | init(_ value: Wrapped) { 200 | self.value = value 201 | } 202 | } 203 | 204 | extension RedBlackTree2 { 205 | public struct Index { 206 | fileprivate weak var root: Node? 207 | fileprivate let mutationCount: Int64? 208 | 209 | fileprivate var path: [Weak] 210 | 211 | fileprivate init(root: Node?, path: [Weak]) { 212 | self.root = root 213 | self.mutationCount = root?.mutationCount 214 | self.path = path 215 | } 216 | } 217 | } 218 | 219 | extension RedBlackTree2 { 220 | public var endIndex: Index { 221 | return Index(root: root, path: []) 222 | } 223 | 224 | // - Complexity: O(log(n)); this violates `Collection` requirements. 225 | public var startIndex: Index { 226 | var path: [Weak] = [] 227 | var node = root 228 | while let n = node { 229 | path.append(Weak(n)) 230 | node = n.left 231 | } 232 | return Index(root: root, path: path) 233 | } 234 | } 235 | 236 | extension RedBlackTree2.Index { 237 | fileprivate func isValid(for root: RedBlackTree2.Node?) -> Bool { 238 | return self.root === root 239 | && self.mutationCount == root?.mutationCount 240 | } 241 | } 242 | 243 | extension RedBlackTree2.Index { 244 | fileprivate static func validate(_ left: RedBlackTree2.Index, _ right: RedBlackTree2.Index) -> Bool { 245 | return left.root === right.root 246 | && left.mutationCount == right.mutationCount 247 | && left.mutationCount == left.root?.mutationCount 248 | } 249 | } 250 | 251 | extension RedBlackTree2 { 252 | public subscript(_ index: Index) -> Element { 253 | precondition(index.isValid(for: root)) 254 | return index.path.last!.value!.value 255 | } 256 | } 257 | 258 | extension RedBlackTree2.Index { 259 | /// Precondition: `self` is a valid index. 260 | fileprivate var current: RedBlackTree2.Node? { 261 | guard let ref = path.last else { return nil } 262 | return ref.value! 263 | } 264 | } 265 | 266 | extension RedBlackTree2.Index: Comparable { 267 | public static func ==(left: RedBlackTree2.Index, right: RedBlackTree2.Index) -> Bool { 268 | precondition(RedBlackTree2.Index.validate(left, right)) 269 | return left.current === right.current 270 | } 271 | 272 | public static func <(left: RedBlackTree2.Index, right: RedBlackTree2.Index) -> Bool { 273 | precondition(RedBlackTree2.Index.validate(left, right)) 274 | switch (left.current, right.current) { 275 | case let (a?, b?): 276 | return a.value < b.value 277 | case (nil, _): 278 | return false 279 | default: 280 | return true 281 | } 282 | } 283 | } 284 | 285 | extension RedBlackTree2 { 286 | public func formIndex(after index: inout Index) { 287 | precondition(index.isValid(for: root)) 288 | index.formSuccessor() 289 | } 290 | 291 | public func index(after index: Index) -> Index { 292 | var result = index 293 | self.formIndex(after: &result) 294 | return result 295 | } 296 | } 297 | 298 | extension RedBlackTree2.Index { 299 | /// Precondition: `self` is a valid index other than `endIndex`. 300 | mutating func formSuccessor() { 301 | guard let node = current else { preconditionFailure() } 302 | if var n = node.right { 303 | path.append(Weak(n)) 304 | while let next = n.left { 305 | path.append(Weak(next)) 306 | n = next 307 | } 308 | } 309 | else { 310 | path.removeLast() 311 | var n = node 312 | while let parent = self.current { 313 | if parent.left === n { return } 314 | n = parent 315 | path.removeLast() 316 | } 317 | } 318 | } 319 | } 320 | 321 | extension RedBlackTree2 { 322 | public func formIndex(before index: inout Index) { 323 | precondition(index.isValid(for: root)) 324 | index.formPredecessor() 325 | } 326 | 327 | public func index(before index: Index) -> Index { 328 | var result = index 329 | self.formIndex(before: &result) 330 | return result 331 | } 332 | } 333 | 334 | extension RedBlackTree2.Index { 335 | /// Precondition: `self` is a valid index other than `startIndex`. 336 | mutating func formPredecessor() { 337 | let current = self.current 338 | precondition(current != nil || root != nil) 339 | if var n = (current == nil ? root : current!.left) { 340 | path.append(Weak(n)) 341 | while let next = n.right { 342 | path.append(Weak(next)) 343 | n = next 344 | } 345 | } 346 | else { 347 | path.removeLast() 348 | var n = current 349 | while let parent = self.current { 350 | if parent.right === n { return } 351 | n = parent 352 | path.removeLast() 353 | } 354 | } 355 | } 356 | } 357 | 358 | extension RedBlackTree2 { 359 | public struct Iterator: IteratorProtocol { 360 | let tree: RedBlackTree2 361 | var index: RedBlackTree2.Index 362 | 363 | init(_ tree: RedBlackTree2) { 364 | self.tree = tree 365 | self.index = tree.startIndex 366 | } 367 | 368 | public mutating func next() -> Element? { 369 | if index.path.isEmpty { return nil } 370 | defer { index.formSuccessor() } 371 | return index.path.last!.value!.value 372 | } 373 | } 374 | } 375 | 376 | extension RedBlackTree2 { 377 | public func makeIterator() -> Iterator { 378 | return Iterator(self) 379 | } 380 | } 381 | -------------------------------------------------------------------------------- /Sources/SillySet.swift: -------------------------------------------------------------------------------- 1 | struct SillySet: SortedSet, RandomAccessCollection { 2 | typealias Indices = CountableRange 3 | 4 | class Storage { 5 | var v: [Element] 6 | var s: Set 7 | var extras: Set = [] 8 | 9 | init(_ v: [Element]) { 10 | self.v = v 11 | self.s = Set(v) 12 | } 13 | 14 | func commit() { 15 | guard !extras.isEmpty else { return } 16 | s.formUnion(extras) 17 | v += extras 18 | v.sort() 19 | extras = [] 20 | } 21 | } 22 | 23 | private var storage = Storage([]) 24 | 25 | var startIndex: Int { return 0 } 26 | 27 | var endIndex: Int { return storage.s.count + storage.extras.count } 28 | 29 | // Complexity: `O(n*log(n))`, where `n` is the number of insertions since the last time `subscript` was called. 30 | subscript(i: Int) -> Element { 31 | storage.commit() 32 | return storage.v[i] 33 | } 34 | 35 | // Complexity: O(1) 36 | func contains(_ element: Element) -> Bool { 37 | return storage.s.contains(element) || storage.extras.contains(element) 38 | } 39 | 40 | // Complexity: O(1) unless storage is shared. 41 | mutating func insert(_ element: Element) -> (inserted: Bool, memberAfterInsert: Element) { 42 | if !isKnownUniquelyReferenced(&storage) { 43 | storage = Storage(storage.v) 44 | } 45 | if let i = storage.s.index(of: element) { return (false, storage.s[i]) } 46 | return storage.extras.insert(element) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SortedArray.swift: -------------------------------------------------------------------------------- 1 | public struct SortedArray: SortedSet { 2 | fileprivate var storage: [Element] = [] 3 | 4 | public init() {} 5 | } 6 | 7 | extension SortedArray { 8 | func index(for element: Element) -> Int { 9 | var start = 0 10 | var end = storage.count 11 | while start < end { 12 | let middle = start + (end - start) / 2 13 | if element > storage[middle] { 14 | start = middle + 1 15 | } 16 | else { 17 | end = middle 18 | } 19 | } 20 | return start 21 | } 22 | } 23 | 24 | extension SortedArray { 25 | public func index(of element: Element) -> Int? { 26 | let index = self.index(for: element) 27 | guard index < count, storage[index] == element else { return nil } 28 | return index 29 | } 30 | } 31 | 32 | extension SortedArray { 33 | public func contains(_ element: Element) -> Bool { 34 | let index = self.index(for: element) 35 | return index < count && storage[index] == element 36 | } 37 | } 38 | 39 | extension SortedArray { 40 | public func forEach(_ body: (Element) throws -> Void) rethrows { 41 | try storage.forEach(body) 42 | } 43 | } 44 | 45 | extension SortedArray { 46 | public func sorted() -> [Element] { 47 | return storage 48 | } 49 | } 50 | 51 | extension SortedArray { 52 | @discardableResult 53 | public mutating func insert(_ newElement: Element) -> (inserted: Bool, memberAfterInsert: Element) 54 | { 55 | let index = self.index(for: newElement) 56 | if index < count && storage[index] == newElement { 57 | return (false, storage[index]) 58 | } 59 | storage.insert(newElement, at: index) 60 | return (true, newElement) 61 | } 62 | } 63 | 64 | extension SortedArray: RandomAccessCollection { 65 | public typealias Indices = CountableRange 66 | 67 | public var startIndex: Int { return storage.startIndex } 68 | public var endIndex: Int { return storage.endIndex } 69 | 70 | public subscript(index: Int) -> Element { return storage[index] } 71 | } 72 | 73 | extension SortedArray { 74 | func index2(for element: Element) -> Int { 75 | var start = 0 76 | var end = storage.count 77 | while start < end { 78 | let middle = start + (end - start) / 2 + (end - start) >> 6 79 | if element > storage[middle] { 80 | start = middle + 1 81 | } 82 | else { 83 | end = middle 84 | } 85 | } 86 | return start 87 | } 88 | 89 | public func contains2(_ element: Element) -> Bool { 90 | let index = self.index2(for: element) 91 | return index < count && storage[index] == element 92 | } 93 | 94 | func index3(for element: Element) -> Int { 95 | var start = 0 96 | var end = storage.count 97 | while start < end { 98 | let diff = end - start 99 | if diff < 1024 { 100 | let middle = start + diff >> 1 101 | if element > storage[middle] { 102 | start = middle + 1 103 | } 104 | else { 105 | end = middle 106 | } 107 | } 108 | else { 109 | let third = diff / 3 110 | let m1 = start + third 111 | let m2 = end - third 112 | let v1 = storage[m1] 113 | let v2 = storage[m2] 114 | if element < v1 { 115 | end = m1 116 | } 117 | else if element > v2 { 118 | start = m2 + 1 119 | } 120 | else { 121 | start = m1 122 | end = m2 + 1 123 | } 124 | } 125 | } 126 | return start 127 | } 128 | 129 | public func contains3(_ element: Element) -> Bool { 130 | let index = self.index3(for: element) 131 | return index < count && storage[index] == element 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Sources/SortedSet.swift: -------------------------------------------------------------------------------- 1 | public protocol SortedSet: BidirectionalCollection, CustomStringConvertible, CustomPlaygroundQuickLookable { 2 | associatedtype Element: Comparable 3 | 4 | init() 5 | func contains(_ element: Element) -> Bool 6 | mutating func insert(_ newElement: Element) -> (inserted: Bool, memberAfterInsert: Element) 7 | } 8 | 9 | extension SortedSet { 10 | public var description: String { 11 | let contents = self.lazy.map { "\($0)" }.joined(separator: ", ") 12 | return "[\(contents)]" 13 | } 14 | } 15 | 16 | #if os(iOS) 17 | import UIKit 18 | 19 | extension PlaygroundQuickLook { 20 | public static func monospacedText(_ string: String) -> PlaygroundQuickLook { 21 | let text = NSMutableAttributedString(string: string) 22 | let range = NSRange(location: 0, length: text.length) 23 | let style = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle 24 | style.lineSpacing = 0 25 | style.alignment = .left 26 | style.maximumLineHeight = 17 27 | text.addAttribute(NSFontAttributeName, value: UIFont(name: "Menlo", size: 13)!, range: range) 28 | text.addAttribute(NSParagraphStyleAttributeName, value: style, range: range) 29 | return PlaygroundQuickLook.attributedString(text) 30 | } 31 | } 32 | #endif 33 | 34 | extension SortedSet { 35 | public var customPlaygroundQuickLook: PlaygroundQuickLook { 36 | #if os(iOS) 37 | return .monospacedText(String(describing: self)) 38 | #else 39 | return .text(String(describing: self)) 40 | #endif 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/main.swift: -------------------------------------------------------------------------------- 1 | do { 2 | print((0 ..< 20).shuffled()) 3 | print((0 ..< 20).shuffled()) 4 | print((0 ..< 20).shuffled()) 5 | } 6 | 7 | do { 8 | var a = [2, 3, 4] 9 | var b = a 10 | a.insert(1, at: 0) 11 | print(a) 12 | print(b) 13 | } 14 | 15 | do { 16 | var set = SortedArray() 17 | for i in (0 ..< 22).shuffled() { 18 | set.insert(2 * i) 19 | } 20 | print(set) 21 | 22 | print(set.contains(42)) 23 | 24 | print(set.contains(13)) 25 | 26 | let copy = set 27 | set.insert(13) 28 | 29 | print(set.contains(13)) 30 | 31 | print(copy.contains(13)) 32 | } 33 | 34 | do { 35 | var set = OrderedSet() 36 | for i in (1 ... 20).shuffled() { 37 | set.insert(i) 38 | } 39 | 40 | print(set) 41 | 42 | print(set.contains(7)) 43 | print(set.contains(42)) 44 | 45 | print(set.reduce(0, +)) 46 | 47 | let copy = set 48 | set.insert(42) 49 | print(copy) 50 | print(set) 51 | } 52 | 53 | import Foundation 54 | 55 | struct Value: Comparable { 56 | let value: Int 57 | init(_ value: Int) { self.value = value } 58 | 59 | static func ==(left: Value, right: Value) -> Bool { 60 | return left.value == right.value 61 | } 62 | 63 | static func <(left: Value, right: Value) -> Bool { 64 | return left.value < right.value 65 | } 66 | } 67 | 68 | do { 69 | let value = Value(42) 70 | let a = value as AnyObject 71 | let b = value as AnyObject 72 | print(a.isEqual(b)) 73 | print(a.hash) 74 | print(b.hash) 75 | 76 | var values = OrderedSet() 77 | (1 ... 20).shuffled().map(Value.init).forEach { values.insert($0) } 78 | print(values.contains(Value(7))) 79 | print(values.contains(Value(42))) 80 | } 81 | 82 | do { 83 | let emptyTree: RedBlackTree = .empty 84 | print(emptyTree) 85 | 86 | let tinyTree: RedBlackTree = .node(.black, 42, .empty, .empty) 87 | print(tinyTree) 88 | 89 | let smallTree: RedBlackTree = 90 | .node(.black, 2, 91 | .node(.red, 1, .empty, .empty), 92 | .node(.red, 3, .empty, .empty)) 93 | print(smallTree) 94 | 95 | let bigTree: RedBlackTree = 96 | .node(.black, 9, 97 | .node(.red, 5, 98 | .node(.black, 1, .empty, .node(.red, 4, .empty, .empty)), 99 | .node(.black, 8, .empty, .empty)), 100 | .node(.red, 12, 101 | .node(.black, 11, .empty, .empty), 102 | .node(.black, 16, 103 | .node(.red, 14, .empty, .empty), 104 | .node(.red, 17, .empty, .empty)))) 105 | print(bigTree) 106 | 107 | var set = RedBlackTree.empty 108 | for i in (1 ... 20).shuffled() { 109 | set.insert(i) 110 | } 111 | print(set) 112 | 113 | print(set.lazy.filter { $0 % 2 == 0 }.map { "\($0)" }.joined(separator: ", ")) 114 | } 115 | 116 | do { 117 | var set = RedBlackTree2() 118 | for i in (1 ... 20).shuffled() { 119 | set.insert(i) 120 | } 121 | print(set) 122 | 123 | print(set.contains(13)) 124 | 125 | print(set.contains(42)) 126 | 127 | print(set.filter { $0 % 2 == 0 }) 128 | } 129 | 130 | do { 131 | var set = BTree(order: 5) 132 | for i in (1 ... 250).shuffled() { 133 | set.insert(i) 134 | } 135 | print(set) 136 | 137 | let evenMembers = set.reversed().lazy.filter { $0 % 2 == 0 }.map { "\($0)" }.joined(separator: ", ") 138 | print(evenMembers) 139 | } 140 | 141 | do { 142 | func factorial(_ n: Int) -> Int { 143 | return (1 ... max(1, n)).reduce(1, *) 144 | } 145 | print(factorial(4)) 146 | print(factorial(10)) 147 | 148 | var set = Set() // "set" is also a keyword for defining property setters 149 | set.insert(42) 150 | print(set.contains(42)) 151 | } 152 | --------------------------------------------------------------------------------