├── .gitignore ├── AppIcon.appiconset ├── Contents.json ├── Icon-60@2x.png ├── Icon-60@3x.png ├── Icon-76.png ├── Icon-76@2x.png ├── Icon-83.5@2x.png ├── Icon-Small-40.png ├── Icon-Small-40@2x.png ├── Icon-Small-40@3x.png ├── Icon-Small.png ├── Icon-Small@2x.png └── Icon-Small@3x.png ├── Cartfile.private ├── Cartfile.resolved ├── Forest.podspec ├── Forest.xcodeproj ├── Configs │ └── Universal.xcconfig ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── Forest.xcscheme ├── Forest ├── Forest.h └── Info.plist ├── ForestBenchmark ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── BinarySearchTreeBenchmarkDelegate.swift ├── Info.plist └── ViewController.swift ├── ForestDemo ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-76.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-83.5@2x.png │ │ ├── Icon-Notification.png │ │ ├── Icon-Notification@2x.png │ │ ├── Icon-Notification@3x.png │ │ ├── Icon-Small-40.png │ │ ├── Icon-Small-40@2x.png │ │ ├── Icon-Small-40@3x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ └── LaunchImage.launchimage │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── BenchmarkCell.xib ├── BinarySearchTreeBenchmark.swift ├── BinarySearchTreeBenchmarkDelegate.swift ├── BinarySearchTreeViewController.swift ├── BinarySearchTreeViewController.xib ├── DetailViewController.swift ├── Info.plist ├── MasterViewController.swift └── TreeDemo.swift ├── ForestTests ├── AVLTreeTests.swift ├── BinaryTreeTests.swift ├── Info.plist └── RBTreeTests.swift ├── Icon.sketch ├── Jumbotron.png ├── LICENSE ├── Package.swift ├── README.md ├── Sources ├── BinarySearchTrees │ ├── AVLTree.swift │ ├── BinarySearchTreeType.swift │ ├── GrowableBinarySearchTreeType.swift │ ├── MutableBinarySearchTreeType.swift │ ├── PrunableBinarySearchTreeType.swift │ └── RBTree.swift ├── BinaryTrees │ ├── BinaryTree.swift │ └── BinaryTreeType.swift └── CountableRange+Extensions.swift └── Tests ├── Forest ├── AVLTreeTests.swift ├── BinaryTreeTests.swift ├── ForestTests.swift ├── KDTreeTests.swift └── RBTreeTests.swift └── LinuxMain.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | .DS_Store 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xcuserstate 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | /Carthage 69 | -------------------------------------------------------------------------------- /AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Small@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-Small@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Small-40@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Small-40@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-60@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-60@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "29x29", 41 | "idiom" : "ipad", 42 | "filename" : "Icon-Small.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "Icon-Small@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "40x40", 53 | "idiom" : "ipad", 54 | "filename" : "Icon-Small-40.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-Small-40@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "76x76", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-76.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-76@2x.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "83.5x83.5", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-83.5@2x.png", 79 | "scale" : "2x" 80 | } 81 | ] 82 | } -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-Small-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-Small-40.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Cartfile.private: -------------------------------------------------------------------------------- 1 | github "Quick/Quick" ~> 1.0.0 2 | github "Quick/Nimble" ~> 5.1.1 3 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "Quick/Nimble" "v5.1.1" 2 | github "Quick/Quick" "v1.0.0" 3 | -------------------------------------------------------------------------------- /Forest.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "Forest" 4 | s.version = "0.1.0" 5 | s.summary = "A collection of persistent immutable trees." 6 | 7 | s.description = <<-DESC 8 | A collection of persistent immutable trees. 9 | DESC 10 | 11 | s.homepage = "https://github.com/regexident/Forest" 12 | s.license = { :type => 'BSD-3', :file => 'LICENSE' } 13 | s.author = { "Vincent Esche" => "regexident@gmail.com" } 14 | s.source = { :git => "https://github.com/regexident/Forest.git", :tag => '0.1.0' } 15 | s.source_files = "Forest/Classes/*.{swift,h,m}" 16 | # s.public_header_files = "Forest/*.h" 17 | s.requires_arc = true 18 | s.osx.deployment_target = "10.9" 19 | s.ios.deployment_target = "8.0" 20 | 21 | end 22 | -------------------------------------------------------------------------------- /Forest.xcodeproj/Configs/Universal.xcconfig: -------------------------------------------------------------------------------- 1 | PRODUCT_NAME = $(TARGET_NAME) 2 | SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator 3 | DYLIB_INSTALL_NAME_BASE = @rpath 4 | OTHER_SWIFT_FLAGS = -DXcode 5 | -------------------------------------------------------------------------------- /Forest.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A421BD8B1A9CCB320032CF28 /* Forest.h in Headers */ = {isa = PBXBuildFile; fileRef = A421BD8A1A9CCB320032CF28 /* Forest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | A421BD911A9CCB320032CF28 /* Forest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A421BD851A9CCB320032CF28 /* Forest.framework */; }; 12 | A480449D1B740806002452BA /* BinaryTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A480449C1B740806002452BA /* BinaryTreeTests.swift */; }; 13 | A48044A01B740F79002452BA /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A480449E1B740F79002452BA /* Nimble.framework */; }; 14 | A48044A11B740F79002452BA /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A480449F1B740F79002452BA /* Quick.framework */; }; 15 | A48044A31B740FA5002452BA /* Nimble.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A480449E1B740F79002452BA /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | A48044A41B740FA5002452BA /* Quick.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A480449F1B740F79002452BA /* Quick.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | A48044A81B7429EA002452BA /* AVLTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A421BDA11A9CCB6F0032CF28 /* AVLTreeTests.swift */; }; 18 | A48044A91B7429EA002452BA /* RBTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A41B30AF1AE55DA100898A35 /* RBTreeTests.swift */; }; 19 | BF37D7691E54DA02003D1F87 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF37D7681E54DA02003D1F87 /* AppDelegate.swift */; }; 20 | BF37D76B1E54DA02003D1F87 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF37D76A1E54DA02003D1F87 /* ViewController.swift */; }; 21 | BF37D76D1E54DA02003D1F87 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF37D76C1E54DA02003D1F87 /* Assets.xcassets */; }; 22 | BF37D7701E54DA02003D1F87 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF37D76E1E54DA02003D1F87 /* Main.storyboard */; }; 23 | BF37D7751E54DA24003D1F87 /* Forest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A421BD851A9CCB320032CF28 /* Forest.framework */; }; 24 | BF37D7761E54DA24003D1F87 /* Forest.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A421BD851A9CCB320032CF28 /* Forest.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 25 | BF37D77B1E54DC69003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF37D77A1E54DC69003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift */; }; 26 | BF37D77C1E54DC91003D1F87 /* BinarySearchTreeBenchmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = A437ED331B6DA800002452BA /* BinarySearchTreeBenchmark.swift */; }; 27 | BF37D77E1E54DCDD003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF37D77D1E54DCDD003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift */; }; 28 | BF3C50061E2FF904005569E1 /* Forest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A421BD851A9CCB320032CF28 /* Forest.framework */; }; 29 | BF3C50071E2FF904005569E1 /* Forest.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A421BD851A9CCB320032CF28 /* Forest.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 30 | BF3C500B1E2FF9A7005569E1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A437ED0C1B6D7953002452BA /* AppDelegate.swift */; }; 31 | BF3C500C1E2FF9A7005569E1 /* TreeDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A437ED1E1B6D7C02002452BA /* TreeDemo.swift */; }; 32 | BF3C500D1E2FF9A7005569E1 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A437ED0E1B6D7953002452BA /* MasterViewController.swift */; }; 33 | BF3C500E1E2FF9A7005569E1 /* BinarySearchTreeBenchmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = A437ED331B6DA800002452BA /* BinarySearchTreeBenchmark.swift */; }; 34 | BF3C500F1E2FF9A7005569E1 /* BinarySearchTreeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A437ED201B6D7E66002452BA /* BinarySearchTreeViewController.swift */; }; 35 | BF3C50101E2FF9A7005569E1 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A437ED101B6D7953002452BA /* DetailViewController.swift */; }; 36 | BF3C50111E2FF9C2005569E1 /* BinarySearchTreeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A437ED2B1B6D9064002452BA /* BinarySearchTreeViewController.xib */; }; 37 | BF3C50121E2FF9C5005569E1 /* BenchmarkCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A437ED2F1B6D91F4002452BA /* BenchmarkCell.xib */; }; 38 | BF3C50131E2FF9C9005569E1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A437ED121B6D7953002452BA /* Main.storyboard */; }; 39 | BF3C50141E2FF9CC005569E1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A437ED171B6D7953002452BA /* LaunchScreen.storyboard */; }; 40 | BF3C50151E2FF9CF005569E1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A437ED151B6D7953002452BA /* Assets.xcassets */; }; 41 | BFA5F60D1D22DB66001A9307 /* AVLTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5F51D22DB66001A9307 /* AVLTree.swift */; }; 42 | BFA5F60E1D22DB66001A9307 /* BinarySearchTreeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5F61D22DB66001A9307 /* BinarySearchTreeType.swift */; }; 43 | BFA5F60F1D22DB66001A9307 /* GrowableBinarySearchTreeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5F71D22DB66001A9307 /* GrowableBinarySearchTreeType.swift */; }; 44 | BFA5F6101D22DB66001A9307 /* MutableBinarySearchTreeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5F81D22DB66001A9307 /* MutableBinarySearchTreeType.swift */; }; 45 | BFA5F6111D22DB66001A9307 /* RBTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5F91D22DB66001A9307 /* RBTree.swift */; }; 46 | BFA5F6121D22DB66001A9307 /* PrunableBinarySearchTreeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5FA1D22DB66001A9307 /* PrunableBinarySearchTreeType.swift */; }; 47 | BFA5F6131D22DB66001A9307 /* BinaryTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5FC1D22DB66001A9307 /* BinaryTree.swift */; }; 48 | BFA5F6161D22DB66001A9307 /* BinaryTreeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F5FF1D22DB66001A9307 /* BinaryTreeType.swift */; }; 49 | BFA5F6181D22DB66001A9307 /* CountableRange+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA5F6011D22DB66001A9307 /* CountableRange+Extensions.swift */; }; 50 | /* End PBXBuildFile section */ 51 | 52 | /* Begin PBXContainerItemProxy section */ 53 | A421BD921A9CCB320032CF28 /* PBXContainerItemProxy */ = { 54 | isa = PBXContainerItemProxy; 55 | containerPortal = A421BD7C1A9CCB320032CF28 /* Project object */; 56 | proxyType = 1; 57 | remoteGlobalIDString = A421BD841A9CCB320032CF28; 58 | remoteInfo = Forest; 59 | }; 60 | BF37D7771E54DA24003D1F87 /* PBXContainerItemProxy */ = { 61 | isa = PBXContainerItemProxy; 62 | containerPortal = A421BD7C1A9CCB320032CF28 /* Project object */; 63 | proxyType = 1; 64 | remoteGlobalIDString = A421BD841A9CCB320032CF28; 65 | remoteInfo = Forest; 66 | }; 67 | BF3C50081E2FF904005569E1 /* PBXContainerItemProxy */ = { 68 | isa = PBXContainerItemProxy; 69 | containerPortal = A421BD7C1A9CCB320032CF28 /* Project object */; 70 | proxyType = 1; 71 | remoteGlobalIDString = A421BD841A9CCB320032CF28; 72 | remoteInfo = Forest; 73 | }; 74 | /* End PBXContainerItemProxy section */ 75 | 76 | /* Begin PBXCopyFilesBuildPhase section */ 77 | A48044A21B740F98002452BA /* Embed Frameworks */ = { 78 | isa = PBXCopyFilesBuildPhase; 79 | buildActionMask = 2147483647; 80 | dstPath = ""; 81 | dstSubfolderSpec = 10; 82 | files = ( 83 | A48044A31B740FA5002452BA /* Nimble.framework in Embed Frameworks */, 84 | A48044A41B740FA5002452BA /* Quick.framework in Embed Frameworks */, 85 | ); 86 | name = "Embed Frameworks"; 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | BF37D7791E54DA24003D1F87 /* Embed Frameworks */ = { 90 | isa = PBXCopyFilesBuildPhase; 91 | buildActionMask = 2147483647; 92 | dstPath = ""; 93 | dstSubfolderSpec = 10; 94 | files = ( 95 | BF37D7761E54DA24003D1F87 /* Forest.framework in Embed Frameworks */, 96 | ); 97 | name = "Embed Frameworks"; 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | BF3C500A1E2FF904005569E1 /* Embed Frameworks */ = { 101 | isa = PBXCopyFilesBuildPhase; 102 | buildActionMask = 2147483647; 103 | dstPath = ""; 104 | dstSubfolderSpec = 10; 105 | files = ( 106 | BF3C50071E2FF904005569E1 /* Forest.framework in Embed Frameworks */, 107 | ); 108 | name = "Embed Frameworks"; 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXCopyFilesBuildPhase section */ 112 | 113 | /* Begin PBXFileReference section */ 114 | A41B30AF1AE55DA100898A35 /* RBTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = RBTreeTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 115 | A421BD851A9CCB320032CF28 /* Forest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Forest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 116 | A421BD891A9CCB320032CF28 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 117 | A421BD8A1A9CCB320032CF28 /* Forest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Forest.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 118 | A421BD901A9CCB320032CF28 /* ForestTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ForestTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 119 | A421BD961A9CCB320032CF28 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../../ForestTests/Info.plist; sourceTree = ""; }; 120 | A421BDA11A9CCB6F0032CF28 /* AVLTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AVLTreeTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 121 | A437ED0C1B6D7953002452BA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 122 | A437ED0E1B6D7953002452BA /* MasterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; 123 | A437ED101B6D7953002452BA /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 124 | A437ED131B6D7953002452BA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 125 | A437ED151B6D7953002452BA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 126 | A437ED181B6D7953002452BA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 127 | A437ED1A1B6D7953002452BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 128 | A437ED1E1B6D7C02002452BA /* TreeDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreeDemo.swift; sourceTree = ""; }; 129 | A437ED201B6D7E66002452BA /* BinarySearchTreeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchTreeViewController.swift; sourceTree = ""; }; 130 | A437ED2B1B6D9064002452BA /* BinarySearchTreeViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BinarySearchTreeViewController.xib; sourceTree = ""; }; 131 | A437ED2F1B6D91F4002452BA /* BenchmarkCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BenchmarkCell.xib; sourceTree = ""; }; 132 | A437ED331B6DA800002452BA /* BinarySearchTreeBenchmark.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BinarySearchTreeBenchmark.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 133 | A480449C1B740806002452BA /* BinaryTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BinaryTreeTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 134 | A480449E1B740F79002452BA /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = ../Carthage/Build/Mac/Nimble.framework; sourceTree = ""; }; 135 | A480449F1B740F79002452BA /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = ../Carthage/Build/Mac/Quick.framework; sourceTree = ""; }; 136 | BF37D7661E54DA02003D1F87 /* ForestBenchmark.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ForestBenchmark.app; sourceTree = BUILT_PRODUCTS_DIR; }; 137 | BF37D7681E54DA02003D1F87 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 138 | BF37D76A1E54DA02003D1F87 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 139 | BF37D76C1E54DA02003D1F87 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 140 | BF37D76F1E54DA02003D1F87 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 141 | BF37D7711E54DA02003D1F87 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 142 | BF37D77A1E54DC69003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchTreeBenchmarkDelegate.swift; sourceTree = ""; }; 143 | BF37D77D1E54DCDD003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchTreeBenchmarkDelegate.swift; sourceTree = ""; }; 144 | BF3C4FF41E2FF829005569E1 /* ForestDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ForestDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 145 | BFA5F5E31D22D52E001A9307 /* Universal.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Universal.xcconfig; sourceTree = ""; }; 146 | BFA5F5F51D22DB66001A9307 /* AVLTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AVLTree.swift; sourceTree = ""; }; 147 | BFA5F5F61D22DB66001A9307 /* BinarySearchTreeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinarySearchTreeType.swift; sourceTree = ""; }; 148 | BFA5F5F71D22DB66001A9307 /* GrowableBinarySearchTreeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GrowableBinarySearchTreeType.swift; sourceTree = ""; }; 149 | BFA5F5F81D22DB66001A9307 /* MutableBinarySearchTreeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MutableBinarySearchTreeType.swift; sourceTree = ""; }; 150 | BFA5F5F91D22DB66001A9307 /* RBTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RBTree.swift; sourceTree = ""; }; 151 | BFA5F5FA1D22DB66001A9307 /* PrunableBinarySearchTreeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrunableBinarySearchTreeType.swift; sourceTree = ""; }; 152 | BFA5F5FC1D22DB66001A9307 /* BinaryTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryTree.swift; sourceTree = ""; }; 153 | BFA5F5FF1D22DB66001A9307 /* BinaryTreeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryTreeType.swift; sourceTree = ""; }; 154 | BFA5F6011D22DB66001A9307 /* CountableRange+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CountableRange+Extensions.swift"; sourceTree = ""; }; 155 | /* End PBXFileReference section */ 156 | 157 | /* Begin PBXFrameworksBuildPhase section */ 158 | A421BD811A9CCB320032CF28 /* Frameworks */ = { 159 | isa = PBXFrameworksBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | A421BD8D1A9CCB320032CF28 /* Frameworks */ = { 166 | isa = PBXFrameworksBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | A421BD911A9CCB320032CF28 /* Forest.framework in Frameworks */, 170 | A48044A01B740F79002452BA /* Nimble.framework in Frameworks */, 171 | A48044A11B740F79002452BA /* Quick.framework in Frameworks */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | BF37D7631E54DA02003D1F87 /* Frameworks */ = { 176 | isa = PBXFrameworksBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | BF37D7751E54DA24003D1F87 /* Forest.framework in Frameworks */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | BF3C4FF11E2FF829005569E1 /* Frameworks */ = { 184 | isa = PBXFrameworksBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | BF3C50061E2FF904005569E1 /* Forest.framework in Frameworks */, 188 | ); 189 | runOnlyForDeploymentPostprocessing = 0; 190 | }; 191 | /* End PBXFrameworksBuildPhase section */ 192 | 193 | /* Begin PBXGroup section */ 194 | A404111B1B9E66B2002452BA /* BinaryTrees */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | A480449C1B740806002452BA /* BinaryTreeTests.swift */, 198 | A404111C1B9E66B9002452BA /* BinarySearchTrees */, 199 | ); 200 | name = BinaryTrees; 201 | sourceTree = ""; 202 | }; 203 | A404111C1B9E66B9002452BA /* BinarySearchTrees */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | A421BDA11A9CCB6F0032CF28 /* AVLTreeTests.swift */, 207 | A41B30AF1AE55DA100898A35 /* RBTreeTests.swift */, 208 | ); 209 | name = BinarySearchTrees; 210 | sourceTree = ""; 211 | }; 212 | A421BD7B1A9CCB320032CF28 = { 213 | isa = PBXGroup; 214 | children = ( 215 | BFA5F5E21D22D52E001A9307 /* Configs */, 216 | A421BD871A9CCB320032CF28 /* Forest */, 217 | A421BD941A9CCB320032CF28 /* ForestTests */, 218 | A437ED0B1B6D7953002452BA /* ForestDemo */, 219 | BF37D7671E54DA02003D1F87 /* ForestBenchmark */, 220 | A421BD861A9CCB320032CF28 /* Products */, 221 | ); 222 | sourceTree = ""; 223 | }; 224 | A421BD861A9CCB320032CF28 /* Products */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | A421BD851A9CCB320032CF28 /* Forest.framework */, 228 | A421BD901A9CCB320032CF28 /* ForestTests.xctest */, 229 | BF3C4FF41E2FF829005569E1 /* ForestDemo.app */, 230 | BF37D7661E54DA02003D1F87 /* ForestBenchmark.app */, 231 | ); 232 | name = Products; 233 | sourceTree = ""; 234 | }; 235 | A421BD871A9CCB320032CF28 /* Forest */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | BFA5F5F31D22DB66001A9307 /* Sources */, 239 | A421BD8A1A9CCB320032CF28 /* Forest.h */, 240 | A421BD881A9CCB320032CF28 /* Supporting Files */, 241 | ); 242 | path = Forest; 243 | sourceTree = ""; 244 | }; 245 | A421BD881A9CCB320032CF28 /* Supporting Files */ = { 246 | isa = PBXGroup; 247 | children = ( 248 | A421BD891A9CCB320032CF28 /* Info.plist */, 249 | ); 250 | name = "Supporting Files"; 251 | sourceTree = ""; 252 | }; 253 | A421BD941A9CCB320032CF28 /* ForestTests */ = { 254 | isa = PBXGroup; 255 | children = ( 256 | A404111B1B9E66B2002452BA /* BinaryTrees */, 257 | A48044A51B740FAC002452BA /* Frameworks */, 258 | A421BD951A9CCB320032CF28 /* Supporting Files */, 259 | ); 260 | name = ForestTests; 261 | path = Tests/Forest; 262 | sourceTree = ""; 263 | }; 264 | A421BD951A9CCB320032CF28 /* Supporting Files */ = { 265 | isa = PBXGroup; 266 | children = ( 267 | A421BD961A9CCB320032CF28 /* Info.plist */, 268 | ); 269 | name = "Supporting Files"; 270 | sourceTree = ""; 271 | }; 272 | A437ED0B1B6D7953002452BA /* ForestDemo */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | A437ED0C1B6D7953002452BA /* AppDelegate.swift */, 276 | A437ED1E1B6D7C02002452BA /* TreeDemo.swift */, 277 | A437ED0E1B6D7953002452BA /* MasterViewController.swift */, 278 | A437ED331B6DA800002452BA /* BinarySearchTreeBenchmark.swift */, 279 | BF37D77A1E54DC69003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift */, 280 | A437ED201B6D7E66002452BA /* BinarySearchTreeViewController.swift */, 281 | A437ED2B1B6D9064002452BA /* BinarySearchTreeViewController.xib */, 282 | A437ED2F1B6D91F4002452BA /* BenchmarkCell.xib */, 283 | A437ED101B6D7953002452BA /* DetailViewController.swift */, 284 | A437ED121B6D7953002452BA /* Main.storyboard */, 285 | A437ED151B6D7953002452BA /* Assets.xcassets */, 286 | A437ED171B6D7953002452BA /* LaunchScreen.storyboard */, 287 | A437ED1A1B6D7953002452BA /* Info.plist */, 288 | ); 289 | path = ForestDemo; 290 | sourceTree = ""; 291 | }; 292 | A48044A51B740FAC002452BA /* Frameworks */ = { 293 | isa = PBXGroup; 294 | children = ( 295 | A480449E1B740F79002452BA /* Nimble.framework */, 296 | A480449F1B740F79002452BA /* Quick.framework */, 297 | ); 298 | name = Frameworks; 299 | path = ..; 300 | sourceTree = ""; 301 | }; 302 | BF37D7671E54DA02003D1F87 /* ForestBenchmark */ = { 303 | isa = PBXGroup; 304 | children = ( 305 | BF37D7681E54DA02003D1F87 /* AppDelegate.swift */, 306 | BF37D76A1E54DA02003D1F87 /* ViewController.swift */, 307 | BF37D77D1E54DCDD003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift */, 308 | BF37D76C1E54DA02003D1F87 /* Assets.xcassets */, 309 | BF37D76E1E54DA02003D1F87 /* Main.storyboard */, 310 | BF37D7711E54DA02003D1F87 /* Info.plist */, 311 | ); 312 | path = ForestBenchmark; 313 | sourceTree = ""; 314 | }; 315 | BF3C50171E3000E4005569E1 /* Extensions */ = { 316 | isa = PBXGroup; 317 | children = ( 318 | BFA5F6011D22DB66001A9307 /* CountableRange+Extensions.swift */, 319 | ); 320 | name = Extensions; 321 | sourceTree = ""; 322 | }; 323 | BFA5F5E21D22D52E001A9307 /* Configs */ = { 324 | isa = PBXGroup; 325 | children = ( 326 | BFA5F5E31D22D52E001A9307 /* Universal.xcconfig */, 327 | ); 328 | name = Configs; 329 | path = Forest.xcodeproj/Configs; 330 | sourceTree = SOURCE_ROOT; 331 | }; 332 | BFA5F5F31D22DB66001A9307 /* Sources */ = { 333 | isa = PBXGroup; 334 | children = ( 335 | BFA5F5F41D22DB66001A9307 /* BinarySearchTrees */, 336 | BFA5F5FB1D22DB66001A9307 /* BinaryTrees */, 337 | BF3C50171E3000E4005569E1 /* Extensions */, 338 | ); 339 | path = Sources; 340 | sourceTree = SOURCE_ROOT; 341 | }; 342 | BFA5F5F41D22DB66001A9307 /* BinarySearchTrees */ = { 343 | isa = PBXGroup; 344 | children = ( 345 | BFA5F5F61D22DB66001A9307 /* BinarySearchTreeType.swift */, 346 | BFA5F5F71D22DB66001A9307 /* GrowableBinarySearchTreeType.swift */, 347 | BFA5F5F81D22DB66001A9307 /* MutableBinarySearchTreeType.swift */, 348 | BFA5F5FA1D22DB66001A9307 /* PrunableBinarySearchTreeType.swift */, 349 | BFA5F5F51D22DB66001A9307 /* AVLTree.swift */, 350 | BFA5F5F91D22DB66001A9307 /* RBTree.swift */, 351 | ); 352 | path = BinarySearchTrees; 353 | sourceTree = ""; 354 | }; 355 | BFA5F5FB1D22DB66001A9307 /* BinaryTrees */ = { 356 | isa = PBXGroup; 357 | children = ( 358 | BFA5F5FF1D22DB66001A9307 /* BinaryTreeType.swift */, 359 | BFA5F5FC1D22DB66001A9307 /* BinaryTree.swift */, 360 | ); 361 | path = BinaryTrees; 362 | sourceTree = ""; 363 | }; 364 | /* End PBXGroup section */ 365 | 366 | /* Begin PBXHeadersBuildPhase section */ 367 | A421BD821A9CCB320032CF28 /* Headers */ = { 368 | isa = PBXHeadersBuildPhase; 369 | buildActionMask = 2147483647; 370 | files = ( 371 | A421BD8B1A9CCB320032CF28 /* Forest.h in Headers */, 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | }; 375 | /* End PBXHeadersBuildPhase section */ 376 | 377 | /* Begin PBXNativeTarget section */ 378 | A421BD841A9CCB320032CF28 /* Forest */ = { 379 | isa = PBXNativeTarget; 380 | buildConfigurationList = A421BD9B1A9CCB320032CF28 /* Build configuration list for PBXNativeTarget "Forest" */; 381 | buildPhases = ( 382 | A421BD801A9CCB320032CF28 /* Sources */, 383 | A421BD811A9CCB320032CF28 /* Frameworks */, 384 | A421BD821A9CCB320032CF28 /* Headers */, 385 | A421BD831A9CCB320032CF28 /* Resources */, 386 | ); 387 | buildRules = ( 388 | ); 389 | dependencies = ( 390 | ); 391 | name = Forest; 392 | productName = Forest; 393 | productReference = A421BD851A9CCB320032CF28 /* Forest.framework */; 394 | productType = "com.apple.product-type.framework"; 395 | }; 396 | A421BD8F1A9CCB320032CF28 /* ForestTests */ = { 397 | isa = PBXNativeTarget; 398 | buildConfigurationList = A421BD9E1A9CCB320032CF28 /* Build configuration list for PBXNativeTarget "ForestTests" */; 399 | buildPhases = ( 400 | A421BD8C1A9CCB320032CF28 /* Sources */, 401 | A421BD8D1A9CCB320032CF28 /* Frameworks */, 402 | A421BD8E1A9CCB320032CF28 /* Resources */, 403 | A48044A21B740F98002452BA /* Embed Frameworks */, 404 | ); 405 | buildRules = ( 406 | ); 407 | dependencies = ( 408 | A421BD931A9CCB320032CF28 /* PBXTargetDependency */, 409 | ); 410 | name = ForestTests; 411 | productName = ForestTests; 412 | productReference = A421BD901A9CCB320032CF28 /* ForestTests.xctest */; 413 | productType = "com.apple.product-type.bundle.unit-test"; 414 | }; 415 | BF37D7651E54DA02003D1F87 /* ForestBenchmark */ = { 416 | isa = PBXNativeTarget; 417 | buildConfigurationList = BF37D7721E54DA02003D1F87 /* Build configuration list for PBXNativeTarget "ForestBenchmark" */; 418 | buildPhases = ( 419 | BF37D7621E54DA02003D1F87 /* Sources */, 420 | BF37D7631E54DA02003D1F87 /* Frameworks */, 421 | BF37D7641E54DA02003D1F87 /* Resources */, 422 | BF37D7791E54DA24003D1F87 /* Embed Frameworks */, 423 | ); 424 | buildRules = ( 425 | ); 426 | dependencies = ( 427 | BF37D7781E54DA24003D1F87 /* PBXTargetDependency */, 428 | ); 429 | name = ForestBenchmark; 430 | productName = ForestBenchmark; 431 | productReference = BF37D7661E54DA02003D1F87 /* ForestBenchmark.app */; 432 | productType = "com.apple.product-type.application"; 433 | }; 434 | BF3C4FF31E2FF829005569E1 /* ForestDemo */ = { 435 | isa = PBXNativeTarget; 436 | buildConfigurationList = BF3C50031E2FF829005569E1 /* Build configuration list for PBXNativeTarget "ForestDemo" */; 437 | buildPhases = ( 438 | BF3C4FF01E2FF829005569E1 /* Sources */, 439 | BF3C4FF11E2FF829005569E1 /* Frameworks */, 440 | BF3C4FF21E2FF829005569E1 /* Resources */, 441 | BF3C500A1E2FF904005569E1 /* Embed Frameworks */, 442 | ); 443 | buildRules = ( 444 | ); 445 | dependencies = ( 446 | BF3C50091E2FF904005569E1 /* PBXTargetDependency */, 447 | ); 448 | name = ForestDemo; 449 | productName = ForestDemo; 450 | productReference = BF3C4FF41E2FF829005569E1 /* ForestDemo.app */; 451 | productType = "com.apple.product-type.application"; 452 | }; 453 | /* End PBXNativeTarget section */ 454 | 455 | /* Begin PBXProject section */ 456 | A421BD7C1A9CCB320032CF28 /* Project object */ = { 457 | isa = PBXProject; 458 | attributes = { 459 | LastSwiftMigration = 0700; 460 | LastSwiftUpdateCheck = 0820; 461 | LastUpgradeCheck = 0820; 462 | ORGANIZATIONNAME = Regexident; 463 | TargetAttributes = { 464 | A421BD841A9CCB320032CF28 = { 465 | CreatedOnToolsVersion = 6.3; 466 | DevelopmentTeam = RHSV5Y8MLD; 467 | LastSwiftMigration = 0820; 468 | }; 469 | A421BD8F1A9CCB320032CF28 = { 470 | CreatedOnToolsVersion = 6.3; 471 | DevelopmentTeam = RHSV5Y8MLD; 472 | LastSwiftMigration = 0820; 473 | }; 474 | BF37D7651E54DA02003D1F87 = { 475 | CreatedOnToolsVersion = 8.2.1; 476 | DevelopmentTeam = RHSV5Y8MLD; 477 | ProvisioningStyle = Automatic; 478 | }; 479 | BF3C4FF31E2FF829005569E1 = { 480 | CreatedOnToolsVersion = 8.2.1; 481 | DevelopmentTeam = RHSV5Y8MLD; 482 | ProvisioningStyle = Automatic; 483 | }; 484 | }; 485 | }; 486 | buildConfigurationList = A421BD7F1A9CCB320032CF28 /* Build configuration list for PBXProject "Forest" */; 487 | compatibilityVersion = "Xcode 3.2"; 488 | developmentRegion = English; 489 | hasScannedForEncodings = 0; 490 | knownRegions = ( 491 | en, 492 | Base, 493 | ); 494 | mainGroup = A421BD7B1A9CCB320032CF28; 495 | productRefGroup = A421BD861A9CCB320032CF28 /* Products */; 496 | projectDirPath = ""; 497 | projectRoot = ""; 498 | targets = ( 499 | A421BD841A9CCB320032CF28 /* Forest */, 500 | A421BD8F1A9CCB320032CF28 /* ForestTests */, 501 | BF3C4FF31E2FF829005569E1 /* ForestDemo */, 502 | BF37D7651E54DA02003D1F87 /* ForestBenchmark */, 503 | ); 504 | }; 505 | /* End PBXProject section */ 506 | 507 | /* Begin PBXResourcesBuildPhase section */ 508 | A421BD831A9CCB320032CF28 /* Resources */ = { 509 | isa = PBXResourcesBuildPhase; 510 | buildActionMask = 2147483647; 511 | files = ( 512 | ); 513 | runOnlyForDeploymentPostprocessing = 0; 514 | }; 515 | A421BD8E1A9CCB320032CF28 /* Resources */ = { 516 | isa = PBXResourcesBuildPhase; 517 | buildActionMask = 2147483647; 518 | files = ( 519 | ); 520 | runOnlyForDeploymentPostprocessing = 0; 521 | }; 522 | BF37D7641E54DA02003D1F87 /* Resources */ = { 523 | isa = PBXResourcesBuildPhase; 524 | buildActionMask = 2147483647; 525 | files = ( 526 | BF37D76D1E54DA02003D1F87 /* Assets.xcassets in Resources */, 527 | BF37D7701E54DA02003D1F87 /* Main.storyboard in Resources */, 528 | ); 529 | runOnlyForDeploymentPostprocessing = 0; 530 | }; 531 | BF3C4FF21E2FF829005569E1 /* Resources */ = { 532 | isa = PBXResourcesBuildPhase; 533 | buildActionMask = 2147483647; 534 | files = ( 535 | BF3C50131E2FF9C9005569E1 /* Main.storyboard in Resources */, 536 | BF3C50141E2FF9CC005569E1 /* LaunchScreen.storyboard in Resources */, 537 | BF3C50111E2FF9C2005569E1 /* BinarySearchTreeViewController.xib in Resources */, 538 | BF3C50121E2FF9C5005569E1 /* BenchmarkCell.xib in Resources */, 539 | BF3C50151E2FF9CF005569E1 /* Assets.xcassets in Resources */, 540 | ); 541 | runOnlyForDeploymentPostprocessing = 0; 542 | }; 543 | /* End PBXResourcesBuildPhase section */ 544 | 545 | /* Begin PBXSourcesBuildPhase section */ 546 | A421BD801A9CCB320032CF28 /* Sources */ = { 547 | isa = PBXSourcesBuildPhase; 548 | buildActionMask = 2147483647; 549 | files = ( 550 | BFA5F6101D22DB66001A9307 /* MutableBinarySearchTreeType.swift in Sources */, 551 | BFA5F60F1D22DB66001A9307 /* GrowableBinarySearchTreeType.swift in Sources */, 552 | BFA5F60D1D22DB66001A9307 /* AVLTree.swift in Sources */, 553 | BFA5F6181D22DB66001A9307 /* CountableRange+Extensions.swift in Sources */, 554 | BFA5F6111D22DB66001A9307 /* RBTree.swift in Sources */, 555 | BFA5F6161D22DB66001A9307 /* BinaryTreeType.swift in Sources */, 556 | BFA5F60E1D22DB66001A9307 /* BinarySearchTreeType.swift in Sources */, 557 | BFA5F6131D22DB66001A9307 /* BinaryTree.swift in Sources */, 558 | BFA5F6121D22DB66001A9307 /* PrunableBinarySearchTreeType.swift in Sources */, 559 | ); 560 | runOnlyForDeploymentPostprocessing = 0; 561 | }; 562 | A421BD8C1A9CCB320032CF28 /* Sources */ = { 563 | isa = PBXSourcesBuildPhase; 564 | buildActionMask = 2147483647; 565 | files = ( 566 | A480449D1B740806002452BA /* BinaryTreeTests.swift in Sources */, 567 | A48044A81B7429EA002452BA /* AVLTreeTests.swift in Sources */, 568 | A48044A91B7429EA002452BA /* RBTreeTests.swift in Sources */, 569 | ); 570 | runOnlyForDeploymentPostprocessing = 0; 571 | }; 572 | BF37D7621E54DA02003D1F87 /* Sources */ = { 573 | isa = PBXSourcesBuildPhase; 574 | buildActionMask = 2147483647; 575 | files = ( 576 | BF37D76B1E54DA02003D1F87 /* ViewController.swift in Sources */, 577 | BF37D7691E54DA02003D1F87 /* AppDelegate.swift in Sources */, 578 | BF37D77C1E54DC91003D1F87 /* BinarySearchTreeBenchmark.swift in Sources */, 579 | BF37D77E1E54DCDD003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift in Sources */, 580 | ); 581 | runOnlyForDeploymentPostprocessing = 0; 582 | }; 583 | BF3C4FF01E2FF829005569E1 /* Sources */ = { 584 | isa = PBXSourcesBuildPhase; 585 | buildActionMask = 2147483647; 586 | files = ( 587 | BF3C500F1E2FF9A7005569E1 /* BinarySearchTreeViewController.swift in Sources */, 588 | BF3C500E1E2FF9A7005569E1 /* BinarySearchTreeBenchmark.swift in Sources */, 589 | BF3C500C1E2FF9A7005569E1 /* TreeDemo.swift in Sources */, 590 | BF3C50101E2FF9A7005569E1 /* DetailViewController.swift in Sources */, 591 | BF3C500B1E2FF9A7005569E1 /* AppDelegate.swift in Sources */, 592 | BF37D77B1E54DC69003D1F87 /* BinarySearchTreeBenchmarkDelegate.swift in Sources */, 593 | BF3C500D1E2FF9A7005569E1 /* MasterViewController.swift in Sources */, 594 | ); 595 | runOnlyForDeploymentPostprocessing = 0; 596 | }; 597 | /* End PBXSourcesBuildPhase section */ 598 | 599 | /* Begin PBXTargetDependency section */ 600 | A421BD931A9CCB320032CF28 /* PBXTargetDependency */ = { 601 | isa = PBXTargetDependency; 602 | target = A421BD841A9CCB320032CF28 /* Forest */; 603 | targetProxy = A421BD921A9CCB320032CF28 /* PBXContainerItemProxy */; 604 | }; 605 | BF37D7781E54DA24003D1F87 /* PBXTargetDependency */ = { 606 | isa = PBXTargetDependency; 607 | target = A421BD841A9CCB320032CF28 /* Forest */; 608 | targetProxy = BF37D7771E54DA24003D1F87 /* PBXContainerItemProxy */; 609 | }; 610 | BF3C50091E2FF904005569E1 /* PBXTargetDependency */ = { 611 | isa = PBXTargetDependency; 612 | target = A421BD841A9CCB320032CF28 /* Forest */; 613 | targetProxy = BF3C50081E2FF904005569E1 /* PBXContainerItemProxy */; 614 | }; 615 | /* End PBXTargetDependency section */ 616 | 617 | /* Begin PBXVariantGroup section */ 618 | A437ED121B6D7953002452BA /* Main.storyboard */ = { 619 | isa = PBXVariantGroup; 620 | children = ( 621 | A437ED131B6D7953002452BA /* Base */, 622 | ); 623 | name = Main.storyboard; 624 | sourceTree = ""; 625 | }; 626 | A437ED171B6D7953002452BA /* LaunchScreen.storyboard */ = { 627 | isa = PBXVariantGroup; 628 | children = ( 629 | A437ED181B6D7953002452BA /* Base */, 630 | ); 631 | name = LaunchScreen.storyboard; 632 | sourceTree = ""; 633 | }; 634 | BF37D76E1E54DA02003D1F87 /* Main.storyboard */ = { 635 | isa = PBXVariantGroup; 636 | children = ( 637 | BF37D76F1E54DA02003D1F87 /* Base */, 638 | ); 639 | name = Main.storyboard; 640 | sourceTree = ""; 641 | }; 642 | /* End PBXVariantGroup section */ 643 | 644 | /* Begin XCBuildConfiguration section */ 645 | A421BD991A9CCB320032CF28 /* Debug */ = { 646 | isa = XCBuildConfiguration; 647 | buildSettings = { 648 | ALWAYS_SEARCH_USER_PATHS = NO; 649 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 650 | CLANG_CXX_LIBRARY = "libc++"; 651 | CLANG_ENABLE_MODULES = YES; 652 | CLANG_ENABLE_OBJC_ARC = YES; 653 | CLANG_WARN_BOOL_CONVERSION = YES; 654 | CLANG_WARN_CONSTANT_CONVERSION = YES; 655 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 656 | CLANG_WARN_EMPTY_BODY = YES; 657 | CLANG_WARN_ENUM_CONVERSION = YES; 658 | CLANG_WARN_INFINITE_RECURSION = YES; 659 | CLANG_WARN_INT_CONVERSION = YES; 660 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 661 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 662 | CLANG_WARN_UNREACHABLE_CODE = YES; 663 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 664 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 665 | COPY_PHASE_STRIP = NO; 666 | CURRENT_PROJECT_VERSION = 1; 667 | DEBUG_INFORMATION_FORMAT = dwarf; 668 | ENABLE_STRICT_OBJC_MSGSEND = YES; 669 | ENABLE_TESTABILITY = YES; 670 | GCC_C_LANGUAGE_STANDARD = gnu99; 671 | GCC_DYNAMIC_NO_PIC = NO; 672 | GCC_NO_COMMON_BLOCKS = YES; 673 | GCC_OPTIMIZATION_LEVEL = 0; 674 | GCC_PREPROCESSOR_DEFINITIONS = ( 675 | "DEBUG=1", 676 | "$(inherited)", 677 | ); 678 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 679 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 680 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 681 | GCC_WARN_UNDECLARED_SELECTOR = YES; 682 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 683 | GCC_WARN_UNUSED_FUNCTION = YES; 684 | GCC_WARN_UNUSED_VARIABLE = YES; 685 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 686 | MACOSX_DEPLOYMENT_TARGET = 10.10; 687 | MTL_ENABLE_DEBUG_INFO = YES; 688 | ONLY_ACTIVE_ARCH = YES; 689 | SDKROOT = macosx; 690 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 691 | TARGETED_DEVICE_FAMILY = "1,2"; 692 | VERSIONING_SYSTEM = "apple-generic"; 693 | VERSION_INFO_PREFIX = ""; 694 | }; 695 | name = Debug; 696 | }; 697 | A421BD9A1A9CCB320032CF28 /* Release */ = { 698 | isa = XCBuildConfiguration; 699 | buildSettings = { 700 | ALWAYS_SEARCH_USER_PATHS = NO; 701 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 702 | CLANG_CXX_LIBRARY = "libc++"; 703 | CLANG_ENABLE_MODULES = YES; 704 | CLANG_ENABLE_OBJC_ARC = YES; 705 | CLANG_WARN_BOOL_CONVERSION = YES; 706 | CLANG_WARN_CONSTANT_CONVERSION = YES; 707 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 708 | CLANG_WARN_EMPTY_BODY = YES; 709 | CLANG_WARN_ENUM_CONVERSION = YES; 710 | CLANG_WARN_INFINITE_RECURSION = YES; 711 | CLANG_WARN_INT_CONVERSION = YES; 712 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 713 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 714 | CLANG_WARN_UNREACHABLE_CODE = YES; 715 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 716 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 717 | COPY_PHASE_STRIP = NO; 718 | CURRENT_PROJECT_VERSION = 1; 719 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 720 | ENABLE_NS_ASSERTIONS = NO; 721 | ENABLE_STRICT_OBJC_MSGSEND = YES; 722 | GCC_C_LANGUAGE_STANDARD = gnu99; 723 | GCC_NO_COMMON_BLOCKS = YES; 724 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 725 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 726 | GCC_WARN_UNDECLARED_SELECTOR = YES; 727 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 728 | GCC_WARN_UNUSED_FUNCTION = YES; 729 | GCC_WARN_UNUSED_VARIABLE = YES; 730 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 731 | MACOSX_DEPLOYMENT_TARGET = 10.10; 732 | MTL_ENABLE_DEBUG_INFO = NO; 733 | SDKROOT = macosx; 734 | TARGETED_DEVICE_FAMILY = "1,2"; 735 | VALIDATE_PRODUCT = YES; 736 | VERSIONING_SYSTEM = "apple-generic"; 737 | VERSION_INFO_PREFIX = ""; 738 | }; 739 | name = Release; 740 | }; 741 | A421BD9C1A9CCB320032CF28 /* Debug */ = { 742 | isa = XCBuildConfiguration; 743 | baseConfigurationReference = BFA5F5E31D22D52E001A9307 /* Universal.xcconfig */; 744 | buildSettings = { 745 | CLANG_ENABLE_MODULES = YES; 746 | CODE_SIGN_IDENTITY = "-"; 747 | COMBINE_HIDPI_IMAGES = YES; 748 | DEFINES_MODULE = YES; 749 | DYLIB_COMPATIBILITY_VERSION = 1; 750 | DYLIB_CURRENT_VERSION = 1; 751 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 752 | INFOPLIST_FILE = Forest/Info.plist; 753 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 754 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 755 | PRODUCT_BUNDLE_IDENTIFIER = "com.regexident.$(PRODUCT_NAME:rfc1034identifier)"; 756 | PRODUCT_NAME = "$(TARGET_NAME)"; 757 | SKIP_INSTALL = YES; 758 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 759 | SWIFT_VERSION = 3.0; 760 | }; 761 | name = Debug; 762 | }; 763 | A421BD9D1A9CCB320032CF28 /* Release */ = { 764 | isa = XCBuildConfiguration; 765 | baseConfigurationReference = BFA5F5E31D22D52E001A9307 /* Universal.xcconfig */; 766 | buildSettings = { 767 | CLANG_ENABLE_MODULES = YES; 768 | CODE_SIGN_IDENTITY = "-"; 769 | COMBINE_HIDPI_IMAGES = YES; 770 | DEFINES_MODULE = YES; 771 | DYLIB_COMPATIBILITY_VERSION = 1; 772 | DYLIB_CURRENT_VERSION = 1; 773 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 774 | INFOPLIST_FILE = Forest/Info.plist; 775 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 776 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 777 | PRODUCT_BUNDLE_IDENTIFIER = "com.regexident.$(PRODUCT_NAME:rfc1034identifier)"; 778 | PRODUCT_NAME = "$(TARGET_NAME)"; 779 | SKIP_INSTALL = YES; 780 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 781 | SWIFT_VERSION = 3.0; 782 | }; 783 | name = Release; 784 | }; 785 | A421BD9F1A9CCB320032CF28 /* Debug */ = { 786 | isa = XCBuildConfiguration; 787 | buildSettings = { 788 | COMBINE_HIDPI_IMAGES = YES; 789 | FRAMEWORK_SEARCH_PATHS = ( 790 | "$(SDKROOT)/Developer/Library/Frameworks", 791 | "$(inherited)", 792 | "$(PROJECT_DIR)/Carthage/Build/Mac", 793 | ); 794 | GCC_PREPROCESSOR_DEFINITIONS = ( 795 | "DEBUG=1", 796 | "$(inherited)", 797 | ); 798 | INFOPLIST_FILE = ForestTests/Info.plist; 799 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 800 | PRODUCT_BUNDLE_IDENTIFIER = "com.regexident.$(PRODUCT_NAME:rfc1034identifier)"; 801 | PRODUCT_NAME = "$(TARGET_NAME)"; 802 | SWIFT_VERSION = 3.0; 803 | }; 804 | name = Debug; 805 | }; 806 | A421BDA01A9CCB320032CF28 /* Release */ = { 807 | isa = XCBuildConfiguration; 808 | buildSettings = { 809 | COMBINE_HIDPI_IMAGES = YES; 810 | FRAMEWORK_SEARCH_PATHS = ( 811 | "$(SDKROOT)/Developer/Library/Frameworks", 812 | "$(inherited)", 813 | "$(PROJECT_DIR)/Carthage/Build/Mac", 814 | ); 815 | INFOPLIST_FILE = ForestTests/Info.plist; 816 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 817 | PRODUCT_BUNDLE_IDENTIFIER = "com.regexident.$(PRODUCT_NAME:rfc1034identifier)"; 818 | PRODUCT_NAME = "$(TARGET_NAME)"; 819 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 820 | SWIFT_VERSION = 3.0; 821 | }; 822 | name = Release; 823 | }; 824 | BF37D7731E54DA02003D1F87 /* Debug */ = { 825 | isa = XCBuildConfiguration; 826 | buildSettings = { 827 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 828 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 829 | CLANG_ANALYZER_NONNULL = YES; 830 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 831 | CODE_SIGN_IDENTITY = "-"; 832 | COMBINE_HIDPI_IMAGES = YES; 833 | INFOPLIST_FILE = ForestBenchmark/Info.plist; 834 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 835 | MACOSX_DEPLOYMENT_TARGET = 10.12; 836 | PRODUCT_BUNDLE_IDENTIFIER = com.regexident.ForestBenchmark; 837 | PRODUCT_NAME = "$(TARGET_NAME)"; 838 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 839 | SWIFT_VERSION = 3.0; 840 | }; 841 | name = Debug; 842 | }; 843 | BF37D7741E54DA02003D1F87 /* Release */ = { 844 | isa = XCBuildConfiguration; 845 | buildSettings = { 846 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 847 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 848 | CLANG_ANALYZER_NONNULL = YES; 849 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 850 | CODE_SIGN_IDENTITY = "-"; 851 | COMBINE_HIDPI_IMAGES = YES; 852 | INFOPLIST_FILE = ForestBenchmark/Info.plist; 853 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 854 | MACOSX_DEPLOYMENT_TARGET = 10.12; 855 | PRODUCT_BUNDLE_IDENTIFIER = com.regexident.ForestBenchmark; 856 | PRODUCT_NAME = "$(TARGET_NAME)"; 857 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 858 | SWIFT_VERSION = 3.0; 859 | }; 860 | name = Release; 861 | }; 862 | BF3C50041E2FF829005569E1 /* Debug */ = { 863 | isa = XCBuildConfiguration; 864 | buildSettings = { 865 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 866 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 867 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 868 | CLANG_ANALYZER_NONNULL = YES; 869 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 870 | DEVELOPMENT_TEAM = RHSV5Y8MLD; 871 | INFOPLIST_FILE = ForestDemo/Info.plist; 872 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 873 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 874 | PRODUCT_BUNDLE_IDENTIFIER = "-.ForestDemo"; 875 | PRODUCT_NAME = "$(TARGET_NAME)"; 876 | SDKROOT = iphoneos; 877 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 878 | SWIFT_VERSION = 3.0; 879 | }; 880 | name = Debug; 881 | }; 882 | BF3C50051E2FF829005569E1 /* Release */ = { 883 | isa = XCBuildConfiguration; 884 | buildSettings = { 885 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 886 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 887 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 888 | CLANG_ANALYZER_NONNULL = YES; 889 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 890 | DEVELOPMENT_TEAM = RHSV5Y8MLD; 891 | INFOPLIST_FILE = ForestDemo/Info.plist; 892 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 893 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 894 | PRODUCT_BUNDLE_IDENTIFIER = "-.ForestDemo"; 895 | PRODUCT_NAME = "$(TARGET_NAME)"; 896 | SDKROOT = iphoneos; 897 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 898 | SWIFT_VERSION = 3.0; 899 | }; 900 | name = Release; 901 | }; 902 | /* End XCBuildConfiguration section */ 903 | 904 | /* Begin XCConfigurationList section */ 905 | A421BD7F1A9CCB320032CF28 /* Build configuration list for PBXProject "Forest" */ = { 906 | isa = XCConfigurationList; 907 | buildConfigurations = ( 908 | A421BD991A9CCB320032CF28 /* Debug */, 909 | A421BD9A1A9CCB320032CF28 /* Release */, 910 | ); 911 | defaultConfigurationIsVisible = 0; 912 | defaultConfigurationName = Release; 913 | }; 914 | A421BD9B1A9CCB320032CF28 /* Build configuration list for PBXNativeTarget "Forest" */ = { 915 | isa = XCConfigurationList; 916 | buildConfigurations = ( 917 | A421BD9C1A9CCB320032CF28 /* Debug */, 918 | A421BD9D1A9CCB320032CF28 /* Release */, 919 | ); 920 | defaultConfigurationIsVisible = 0; 921 | defaultConfigurationName = Release; 922 | }; 923 | A421BD9E1A9CCB320032CF28 /* Build configuration list for PBXNativeTarget "ForestTests" */ = { 924 | isa = XCConfigurationList; 925 | buildConfigurations = ( 926 | A421BD9F1A9CCB320032CF28 /* Debug */, 927 | A421BDA01A9CCB320032CF28 /* Release */, 928 | ); 929 | defaultConfigurationIsVisible = 0; 930 | defaultConfigurationName = Release; 931 | }; 932 | BF37D7721E54DA02003D1F87 /* Build configuration list for PBXNativeTarget "ForestBenchmark" */ = { 933 | isa = XCConfigurationList; 934 | buildConfigurations = ( 935 | BF37D7731E54DA02003D1F87 /* Debug */, 936 | BF37D7741E54DA02003D1F87 /* Release */, 937 | ); 938 | defaultConfigurationIsVisible = 0; 939 | defaultConfigurationName = Release; 940 | }; 941 | BF3C50031E2FF829005569E1 /* Build configuration list for PBXNativeTarget "ForestDemo" */ = { 942 | isa = XCConfigurationList; 943 | buildConfigurations = ( 944 | BF3C50041E2FF829005569E1 /* Debug */, 945 | BF3C50051E2FF829005569E1 /* Release */, 946 | ); 947 | defaultConfigurationIsVisible = 0; 948 | defaultConfigurationName = Release; 949 | }; 950 | /* End XCConfigurationList section */ 951 | }; 952 | rootObject = A421BD7C1A9CCB320032CF28 /* Project object */; 953 | } 954 | -------------------------------------------------------------------------------- /Forest.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Forest.xcodeproj/xcshareddata/xcschemes/Forest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Forest/Forest.h: -------------------------------------------------------------------------------- 1 | // 2 | // Forest.h 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 2/24/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Forest. 12 | FOUNDATION_EXPORT double ForestVersionNumber; 13 | 14 | //! Project version string for Forest. 15 | FOUNDATION_EXPORT const unsigned char ForestVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Forest/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ForestBenchmark/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ForestBenchmark 4 | // 5 | // Created by Vincent Esche on 15/02/2017. 6 | // Copyright © 2017 Regexident. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | func applicationDidFinishLaunching(_ aNotification: Notification) { 15 | // Insert code here to initialize your application 16 | } 17 | 18 | func applicationWillTerminate(_ aNotification: Notification) { 19 | // Insert code here to tear down your application 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ForestBenchmark/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /ForestBenchmark/BinarySearchTreeBenchmarkDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinarySearchTreeBenchmarkDelegate.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 15/02/2017. 6 | // Copyright © 2017 Regexident. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | struct BinarySearchTreeBenchmarkDelegate { 12 | let partials = ["Initialize", "Insert", "Search", "Remove"] 13 | 14 | func update(_ partial: Int, string: String) {} 15 | func progress(_ partial: Int, current: Int, total: Int) {} 16 | func done(_ partial: Int, total: Int, seconds: TimeInterval) { 17 | let string = String(format: "%d in %.2f seconds", total, seconds) 18 | print(" \(self.partials[partial]): \(string)") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ForestBenchmark/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2017 Regexident. All rights reserved. 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /ForestBenchmark/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ForestBenchmark 4 | // 5 | // Created by Vincent Esche on 15/02/2017. 6 | // Copyright © 2017 Regexident. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | import Forest 12 | 13 | class ViewController: NSViewController { 14 | 15 | let treeDelegate = BinarySearchTreeBenchmarkDelegate() 16 | let queue = OperationQueue() 17 | 18 | let benchmarks = [ 19 | BinarySearchTreeBenchmark( 20 | title: "Sorted Sequence", 21 | partials: ["Initialize", "Insert", "Search", "Remove"] 22 | ), 23 | BinarySearchTreeBenchmark( 24 | title: "Random Sequence", 25 | partials: ["Initialize", "Insert", "Search", "Remove"] 26 | ) 27 | ] 28 | 29 | override func viewDidLoad() { 30 | super.viewDidLoad() 31 | 32 | DispatchQueue.global().async { 33 | print("AVLTree:") 34 | self.startBenchmarks(treeType: AVLTree.self) 35 | print() 36 | 37 | print("RBTree:") 38 | self.startBenchmarks(treeType: RBTree.self) 39 | print() 40 | } 41 | } 42 | 43 | func startBenchmarks(treeType: T.Type) 44 | where T.Element == Int { 45 | for (section, benchmark) in self.benchmarks.enumerated() { 46 | let tree = treeType.init() 47 | let total = 100_000 48 | let delegate = BinarySearchTreeBenchmarkDelegate() 49 | if section == 0 { 50 | print(" Sorted:") 51 | benchmark.run( 52 | tree, 53 | total: total, 54 | source: BinarySearchTreeSortedSource(), 55 | delegate: delegate 56 | ) 57 | } else { 58 | print(" Randomized:") 59 | benchmark.run( 60 | tree, 61 | total: total, 62 | source: BinarySearchTreeRandomSource(), 63 | delegate: delegate 64 | ) 65 | } 66 | } 67 | print("Done.") 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ForestDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ForestDemo 4 | // 5 | // Created by Vincent Esche on 8/2/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | let splitViewController = self.window!.rootViewController as! UISplitViewController 19 | let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController 20 | navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem 21 | splitViewController.delegate = self 22 | return true 23 | } 24 | 25 | func applicationWillResignActive(_ application: UIApplication) { 26 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 27 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 28 | } 29 | 30 | func applicationDidEnterBackground(_ application: UIApplication) { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | func applicationWillEnterForeground(_ application: UIApplication) { 36 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 37 | } 38 | 39 | func applicationDidBecomeActive(_ application: UIApplication) { 40 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 41 | } 42 | 43 | func applicationWillTerminate(_ application: UIApplication) { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | } 46 | 47 | // MARK: - Split view 48 | 49 | func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { 50 | guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } 51 | guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false } 52 | if topAsDetailController.detailItem == nil { 53 | // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. 54 | return true 55 | } 56 | return false 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Notification@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-Notification@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Small@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Small@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-Small-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-Small-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "Icon-Notification.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-Notification@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-Small.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-Small@2x.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-Small-40.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-Small-40@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-76.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-76@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "16x16", 107 | "idiom" : "mac", 108 | "filename" : "icon_16x16.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "16x16", 113 | "idiom" : "mac", 114 | "filename" : "icon_16x16@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "32x32", 119 | "idiom" : "mac", 120 | "filename" : "icon_32x32.png", 121 | "scale" : "1x" 122 | }, 123 | { 124 | "size" : "32x32", 125 | "idiom" : "mac", 126 | "filename" : "icon_32x32@2x.png", 127 | "scale" : "2x" 128 | }, 129 | { 130 | "size" : "128x128", 131 | "idiom" : "mac", 132 | "filename" : "icon_128x128.png", 133 | "scale" : "1x" 134 | }, 135 | { 136 | "size" : "128x128", 137 | "idiom" : "mac", 138 | "filename" : "icon_128x128@2x.png", 139 | "scale" : "2x" 140 | }, 141 | { 142 | "size" : "256x256", 143 | "idiom" : "mac", 144 | "filename" : "icon_256x256.png", 145 | "scale" : "1x" 146 | }, 147 | { 148 | "size" : "256x256", 149 | "idiom" : "mac", 150 | "filename" : "icon_256x256@2x.png", 151 | "scale" : "2x" 152 | }, 153 | { 154 | "size" : "512x512", 155 | "idiom" : "mac", 156 | "filename" : "icon_512x512.png", 157 | "scale" : "1x" 158 | }, 159 | { 160 | "size" : "512x512", 161 | "idiom" : "mac", 162 | "filename" : "icon_512x512@2x.png", 163 | "scale" : "2x" 164 | } 165 | ] 166 | } -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/ForestDemo/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /ForestDemo/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "ipad", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "1x" 9 | }, 10 | { 11 | "orientation" : "landscape", 12 | "idiom" : "ipad", 13 | "extent" : "full-screen", 14 | "minimum-system-version" : "7.0", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "orientation" : "portrait", 19 | "idiom" : "ipad", 20 | "extent" : "full-screen", 21 | "minimum-system-version" : "7.0", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "orientation" : "landscape", 26 | "idiom" : "ipad", 27 | "extent" : "full-screen", 28 | "minimum-system-version" : "7.0", 29 | "scale" : "2x" 30 | } 31 | ], 32 | "info" : { 33 | "version" : 1, 34 | "author" : "xcode" 35 | } 36 | } -------------------------------------------------------------------------------- /ForestDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ForestDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /ForestDemo/BenchmarkCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /ForestDemo/BinarySearchTreeBenchmark.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinarySearchTreeBenchmark.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 8/2/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import Forest 12 | 13 | protocol BinarySearchTreeBenchmarkSource { 14 | mutating func next() -> Int 15 | var isSorted: Bool { get } 16 | } 17 | 18 | struct BinarySearchTreeSortedSource: BinarySearchTreeBenchmarkSource { 19 | var current: Int = 0 20 | mutating func next() -> Int { 21 | self.current += 1 22 | return self.current 23 | } 24 | var isSorted: Bool { 25 | return true 26 | } 27 | } 28 | 29 | struct BinarySearchTreeRandomSource: BinarySearchTreeBenchmarkSource { 30 | mutating func next() -> Int { 31 | return Int(arc4random()) 32 | } 33 | var isSorted: Bool { 34 | return false 35 | } 36 | } 37 | 38 | protocol BinarySearchTreeBenchmarkType { 39 | func run(_ total: Int, delegate: BinarySearchTreeBenchmarkDelegate) 40 | } 41 | 42 | struct BinarySearchTreeBenchmark { 43 | let title: String 44 | let partials: [String] 45 | 46 | func run( 47 | _ tree: T, 48 | total: Int, 49 | source: BinarySearchTreeBenchmarkSource, 50 | delegate: BinarySearchTreeBenchmarkDelegate 51 | ) where T.Element == Int { 52 | delegate.update(0, string: "Preparing Sequence") 53 | var tree = tree 54 | var source = source 55 | var sequence = [Int]() 56 | for _ in 1...total { 57 | sequence.append(source.next()) 58 | } 59 | delegate.update(0, string: "Initializing…") 60 | let initialize = Date.timeIntervalSinceReferenceDate 61 | tree = (source.isSorted) ? T(sortedSequence: sequence) : T(sequence: sequence) 62 | delegate.done(0, total: total, seconds: Date.timeIntervalSinceReferenceDate - initialize) 63 | 64 | tree = T() 65 | let insert = Date.timeIntervalSinceReferenceDate 66 | for i in 1...total { 67 | if i % 1000 == 0 { 68 | delegate.progress(1, current: i, total: total) 69 | } 70 | let _ = tree.insertInPlace(source.next()) 71 | } 72 | delegate.done(1, total: total, seconds: Date.timeIntervalSinceReferenceDate - insert) 73 | 74 | let search = Date.timeIntervalSinceReferenceDate 75 | for i in 1...total { 76 | if i % 1000 == 0 { 77 | delegate.progress(2, current: i, total: total) 78 | } 79 | let _ = tree.contains(source.next()) 80 | } 81 | delegate.done(2, total: total, seconds: Date.timeIntervalSinceReferenceDate - search) 82 | 83 | let remove = Date.timeIntervalSinceReferenceDate 84 | for i in 1...total { 85 | if i % 1000 == 0 { 86 | delegate.progress(3, current: i, total: total) 87 | } 88 | let _ = tree.removeInPlace(source.next()) 89 | } 90 | delegate.done(3, total: total, seconds: Date.timeIntervalSinceReferenceDate - remove) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /ForestDemo/BinarySearchTreeBenchmarkDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinarySearchTreeBenchmarkDelegate.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 15/02/2017. 6 | // Copyright © 2017 Regexident. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct BinarySearchTreeBenchmarkDelegate { 12 | let labels: [UILabel] 13 | func update(_ partial: Int, string: String) { 14 | DispatchQueue.main.async { 15 | self.labels[partial].text = string 16 | } 17 | } 18 | func progress(_ partial: Int, current: Int, total: Int) { 19 | DispatchQueue.main.async { 20 | self.labels[partial].text = "\(current) / \(total)" 21 | } 22 | } 23 | func done(_ partial: Int, total: Int, seconds: TimeInterval) { 24 | DispatchQueue.main.async { 25 | self.labels[partial].text = String(format: "%d in %.2f seconds", total, seconds) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ForestDemo/BinarySearchTreeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinarySearchTreeViewController.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 8/2/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import Forest 12 | 13 | class BinarySearchTreeViewController: UITableViewController where T.Element == Int { 14 | 15 | typealias Tree = T 16 | 17 | @IBOutlet var headerView: UIView! 18 | @IBOutlet var benchmarkButton: UIButton! 19 | 20 | let benchmarks = [ 21 | BinarySearchTreeBenchmark( 22 | title: "Sorted Sequence", 23 | partials: ["Initialize", "Insert", "Search", "Remove"] 24 | ), 25 | BinarySearchTreeBenchmark( 26 | title: "Random Sequence", 27 | partials: ["Initialize", "Insert", "Search", "Remove"] 28 | ) 29 | ] 30 | 31 | let queue = OperationQueue() 32 | 33 | convenience init() { 34 | self.init(nibName: nil, bundle: nil) 35 | } 36 | 37 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 38 | super.init(nibName: "BinarySearchTreeViewController", bundle: nil) 39 | } 40 | 41 | required init?(coder: NSCoder) { 42 | super.init(coder: coder) 43 | } 44 | 45 | @IBAction func startBenchmarks(_ sender: UIButton) { 46 | DispatchQueue.main.async { 47 | self.benchmarkButton.isEnabled = false 48 | } 49 | var previousOperation: BlockOperation? 50 | for (section, benchmark) in self.benchmarks.enumerated() { 51 | let labels = (0.. UILabel in 52 | let cell = self.tableView.cellForRow(at: IndexPath(row: index, section: section))! 53 | return cell.detailTextLabel! 54 | } 55 | let operation = BlockOperation() { 56 | let tree = Tree() 57 | let total = 100_000 58 | let delegate = BinarySearchTreeBenchmarkDelegate(labels: labels) 59 | if section == 0 { 60 | benchmark.run(tree, total: total, source: BinarySearchTreeSortedSource(), delegate: delegate) 61 | } else { 62 | benchmark.run(tree, total: total, source: BinarySearchTreeRandomSource(), delegate: delegate) 63 | } 64 | } 65 | if let dependency = previousOperation { 66 | operation.addDependency(dependency) 67 | } 68 | previousOperation = operation 69 | self.queue.addOperation(operation) 70 | } 71 | let operation = BlockOperation() { 72 | DispatchQueue.main.async { 73 | self.benchmarkButton.isEnabled = true 74 | } 75 | } 76 | if let dependency = previousOperation { 77 | operation.addDependency(dependency) 78 | } 79 | self.queue.addOperation(operation) 80 | } 81 | 82 | override func viewDidLoad() { 83 | super.viewDidLoad() 84 | 85 | // Do any additional setup after loading the view. 86 | 87 | self.tableView.tableHeaderView = self.headerView 88 | 89 | self.tableView.register(UINib(nibName: "BenchmarkCell", bundle: nil), forCellReuseIdentifier: "Cell") 90 | } 91 | 92 | override func numberOfSections(in tableView: UITableView) -> Int { 93 | return self.benchmarks.count 94 | } 95 | 96 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 97 | return self.benchmarks[section].partials.count 98 | } 99 | 100 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 101 | let benchmarkSection = self.benchmarks[section] 102 | return benchmarkSection.title 103 | } 104 | 105 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 106 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 107 | 108 | let benchmark = self.benchmarks[indexPath.section] 109 | let partial = benchmark.partials[indexPath.row] 110 | 111 | cell.textLabel?.text = partial 112 | cell.detailTextLabel?.text = "0" 113 | return cell 114 | } 115 | 116 | override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { 117 | return false 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /ForestDemo/BinarySearchTreeViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ForestDemo/DetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.swift 3 | // ForestDemo 4 | // 5 | // Created by Vincent Esche on 8/2/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DetailViewController: UIViewController { 12 | 13 | var detailItem: TreeDemo! { 14 | didSet { 15 | // Update the view. 16 | self.configureView() 17 | } 18 | } 19 | 20 | func configureView() { 21 | // Update the user interface for the detail item. 22 | if let detail = self.detailItem { 23 | self.title = detail.title 24 | 25 | let viewController = detail.viewController 26 | self.addChildViewController(viewController) 27 | viewController.view.translatesAutoresizingMaskIntoConstraints = false 28 | viewController.view.frame = self.view.bounds 29 | self.view.addSubview(viewController.view) 30 | 31 | self.view.addConstraint(NSLayoutConstraint(item: viewController.view, attribute: NSLayoutAttribute.top, relatedBy: .equal, toItem: self.topLayoutGuide, attribute: NSLayoutAttribute.bottom, multiplier: 1.0, constant: 0.0)) 32 | self.view.addConstraint(NSLayoutConstraint(item: viewController.view, attribute: NSLayoutAttribute.bottom, relatedBy: .equal, toItem: self.bottomLayoutGuide, attribute: NSLayoutAttribute.top, multiplier: 1.0, constant: 0.0)) 33 | self.view.addConstraint(NSLayoutConstraint(item: viewController.view, attribute: NSLayoutAttribute.left, relatedBy: .equal, toItem: self.view, attribute: NSLayoutAttribute.left, multiplier: 1.0, constant: 0.0)) 34 | self.view.addConstraint(NSLayoutConstraint(item: viewController.view, attribute: NSLayoutAttribute.right, relatedBy: .equal, toItem: self.view, attribute: NSLayoutAttribute.right, multiplier: 1.0, constant: 0.0)) 35 | } 36 | } 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | // Do any additional setup after loading the view, typically from a nib. 41 | self.configureView() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ForestDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ForestDemo/MasterViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MasterViewController.swift 3 | // ForestDemo 4 | // 5 | // Created by Vincent Esche on 8/2/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import Forest 12 | 13 | struct TreeDemoSection { 14 | let title: String 15 | let demos: [TreeDemo] 16 | } 17 | 18 | class MasterViewController: UITableViewController { 19 | 20 | var detailViewController: DetailViewController? = nil 21 | let treeDemoSections: [TreeDemoSection] = [ 22 | TreeDemoSection(title: "Binary Search Trees", demos: [ 23 | TreeDemo(title: "AVLTree", viewController: BinarySearchTreeViewController>()), 24 | TreeDemo(title: "RBTree", viewController: BinarySearchTreeViewController>()) 25 | ]), 26 | ] 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | // Do any additional setup after loading the view, typically from a nib. 31 | 32 | if let split = self.splitViewController { 33 | let controllers = split.viewControllers 34 | self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController 35 | } 36 | } 37 | 38 | override func viewWillAppear(_ animated: Bool) { 39 | self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed 40 | super.viewWillAppear(animated) 41 | } 42 | 43 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 44 | if segue.identifier == "showDetail" { 45 | if let indexPath = self.tableView.indexPathForSelectedRow { 46 | let treeDemoSection = self.treeDemoSections[indexPath.section] 47 | let treeDemo = treeDemoSection.demos[indexPath.row] 48 | let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController 49 | controller.detailItem = treeDemo 50 | controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem 51 | controller.navigationItem.leftItemsSupplementBackButton = true 52 | } 53 | } 54 | } 55 | } 56 | 57 | extension MasterViewController { 58 | override func numberOfSections(in tableView: UITableView) -> Int { 59 | return self.treeDemoSections.count 60 | } 61 | 62 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 63 | return self.treeDemoSections[section].demos.count 64 | } 65 | } 66 | 67 | extension MasterViewController { 68 | 69 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 70 | let treeDemoSection = self.treeDemoSections[section] 71 | return treeDemoSection.title 72 | } 73 | 74 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 75 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 76 | 77 | let treeDemoSection = self.treeDemoSections[indexPath.section] 78 | let treeDemo = treeDemoSection.demos[indexPath.row] 79 | 80 | cell.separatorInset = UIEdgeInsets.zero 81 | cell.textLabel!.text = treeDemo.title 82 | return cell 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ForestDemo/TreeDemo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TreeDemo.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 8/2/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct TreeDemo { 12 | let title: String 13 | let viewController: UIViewController 14 | } 15 | 16 | class BenchmarksCell: UITableViewCell { 17 | @IBOutlet var titleLabel: UILabel! 18 | @IBOutlet var progressView: UIProgressView! 19 | @IBOutlet var progressLabel: UILabel! 20 | } 21 | -------------------------------------------------------------------------------- /ForestTests/AVLTreeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVLTreeTests.swift 3 | // ForestTests 4 | // 5 | // Created by Vincent Esche on 2/4/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | import Forest 13 | 14 | class AVLTreeTests: BinaryTreeTests { 15 | 16 | static func assembleAVLTree(array: [NSObject]) -> AVLTree { 17 | typealias Tree = AVLTree 18 | 19 | let tree: Tree 20 | switch array.count { 21 | case 1: 22 | let element = array[0] as! Int 23 | tree = Tree(Tree(), element, Tree()) 24 | case 2: 25 | if array[0] is Int { 26 | let element = array[0] as! Int 27 | let right = assembleAVLTree(array[1] as! [NSObject]) 28 | tree = Tree(Tree(), element, right) 29 | } else { 30 | let left = assembleAVLTree(array[0] as! [NSObject]) 31 | let element = array[1] as! Int 32 | tree = Tree(left, element, Tree()) 33 | } 34 | case 3: 35 | let left = assembleAVLTree(array[0] as! [NSObject]) 36 | let element = array[1] as! Int 37 | let right = assembleAVLTree(array[2] as! [NSObject]) 38 | tree = Tree(left, element, right) 39 | default: 40 | tree = Tree() 41 | } 42 | return tree 43 | } 44 | 45 | override func spec() { 46 | super.spec() 47 | 48 | self.describe_creatingWithSequence() 49 | self.describe_noRotation() 50 | self.describe_leftRotation() 51 | self.describe_rightRotation() 52 | self.describe_leftRightRotation() 53 | self.describe_rightLeftRotation() 54 | self.describe_insert() 55 | self.describe_remove() 56 | } 57 | 58 | func describe_creatingWithSequence() { 59 | typealias Tree = AVLTree 60 | describe("Creating AVLTree") { 61 | context("from sequence") { 62 | let testTree = AVLTreeTests.assembleAVLTree([ [ [ 1], 2 ], 3, [ [ 4 ], 5 ] ]) 63 | // ┌─ 5 64 | // │ └─ 4 65 | // ┌─ 3 66 | // │ └─ 2 67 | // │ └─ 1 68 | 69 | let tree = Tree(sequence: [1, 2, 3, 4, 5]) 70 | it("it matches expected shape") { 71 | expect(tree).to(equal(testTree)) 72 | } 73 | } 74 | } 75 | } 76 | 77 | func describe_noRotation() { 78 | typealias Tree = AVLTree 79 | describe("Calling rebalance()") { 80 | context("on a balanced tree") { 81 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 82 | // ┌─ 3 83 | // ┌─ 2 84 | // │ └─ 1 85 | 86 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 87 | // ┌─ 3 88 | // ┌─ 2 89 | // │ └─ 1 90 | 91 | let tree = treeBefore.rebalance(0) 92 | it("it remains unchanged") { 93 | expect(tree).to(equal(treeAfter)) 94 | } 95 | } 96 | } 97 | } 98 | 99 | func describe_leftRotation() { 100 | typealias Tree = AVLTree 101 | describe("Calling rebalance()") { 102 | context("on an unbalanced right-right-heavy tree") { 103 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2, [ 3 ] ] ]) 104 | // ┌─ 3 105 | // ┌─ 2 106 | // ┌─ 1 107 | 108 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 109 | // ┌─ 3 110 | // ┌─ 2 111 | // │ └─ 1 112 | 113 | let tree = treeBefore.rebalance(0) 114 | it("it matches expected (balanced) shape") { 115 | expect(tree).to(equal(treeAfter)) 116 | } 117 | } 118 | } 119 | } 120 | 121 | func describe_rightRotation() { 122 | typealias Tree = AVLTree 123 | describe("Calling rebalance()") { 124 | context("on an unbalanced left-left-heavy tree") { 125 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ [ 1 ], 2 ], 3 ]) 126 | // ┌─ 3 127 | // │ └─ 2 128 | // │ └─ 1 129 | 130 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 131 | // ┌─ 3 132 | // ┌─ 2 133 | // │ └─ 1 134 | 135 | let tree = treeBefore.rebalance(0) 136 | it("it matches expected (balanced) shape") { 137 | expect(tree).to(equal(treeAfter)) 138 | } 139 | } 140 | } 141 | } 142 | 143 | func describe_leftRightRotation() { 144 | typealias Tree = AVLTree 145 | describe("Calling rebalance()") { 146 | context("on an unbalanced left-right-heavy tree") { 147 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1, [ 2 ] ], 3 ]) 148 | // ┌─ 3 149 | // │ │ ┌─ 2 150 | // │ └─ 1 151 | 152 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 153 | // ┌─ 3 154 | // ┌─ 2 155 | // │ └─ 1 156 | 157 | let tree = treeBefore.rebalance(0) 158 | it("it matches expected (balanced) shape") { 159 | expect(tree).to(equal(treeAfter)) 160 | } 161 | } 162 | } 163 | } 164 | 165 | func describe_rightLeftRotation() { 166 | typealias Tree = AVLTree 167 | describe("Calling rebalance()") { 168 | context("on an unbalanced left-right-heavy tree") { 169 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ [ 2 ], 3 ] ]) 170 | // ┌─ 3 171 | // │ └─ 2 172 | // ┌─ 1 173 | 174 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 175 | // ┌─ 3 176 | // ┌─ 2 177 | // │ └─ 1 178 | 179 | let tree = treeBefore.rebalance(0) 180 | it("it matches expected (balanced) shape") { 181 | expect(tree).to(equal(treeAfter)) 182 | } 183 | } 184 | } 185 | } 186 | 187 | func describe_insert() { 188 | typealias Tree = AVLTree 189 | describe("Calling insert()") { 190 | context("on an empty tree") { 191 | let treeBefore = AVLTreeTests.assembleAVLTree([ ]) 192 | // ┌─ 193 | 194 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1 ]) 195 | // ┌─ 1 196 | 197 | let tree = treeBefore.insert(1) 198 | it("it matches expected shape") { 199 | expect(tree).to(equal(treeAfter)) 200 | } 201 | } 202 | context("on a root-only tree") { 203 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1 ]) 204 | // ┌─ 1 205 | 206 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1, [ 2 ] ]) 207 | // ┌─ 2 208 | // ┌─ 1 209 | 210 | let tree = treeBefore.insert(2) 211 | it("it matches expected shape") { 212 | expect(tree).to(equal(treeAfter)) 213 | } 214 | } 215 | context("adding a right child to a left-heavy node") { 216 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2 ]) 217 | // ┌─ 2 218 | // │ └─ 1 219 | 220 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 221 | // ┌─ 3 222 | // ┌─ 2 223 | // │ └─ 1 224 | 225 | let tree = treeBefore.insert(3) 226 | it("it matches expected shape") { 227 | expect(tree).to(equal(treeAfter)) 228 | } 229 | } 230 | context("adding a left child to a right-heavy node") { 231 | let treeBefore = AVLTreeTests.assembleAVLTree([ 2, [ 3 ] ]) 232 | // ┌─ 3 233 | // ┌─ 2 234 | 235 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 236 | // ┌─ 3 237 | // ┌─ 2 238 | // │ └─ 1 239 | 240 | let tree = treeBefore.insert(1) 241 | it("it matches expected shape") { 242 | expect(tree).to(equal(treeAfter)) 243 | } 244 | } 245 | context("adding a right child to a right-heavy node") { 246 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2 ]) 247 | // ┌─ 2 248 | // │ └─ 1 249 | 250 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 251 | // ┌─ 3 252 | // ┌─ 2 253 | // │ └─ 1 254 | 255 | let tree = treeBefore.insert(3) 256 | it("it matches expected shape") { 257 | expect(tree).to(equal(treeAfter)) 258 | } 259 | } 260 | context("adding a right child to a right-heavy node") { 261 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2 , [ 3 ] ] ]) 262 | // ┌─ 3 263 | // ┌─ 2 264 | // ┌─ 1 265 | 266 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3, [ 4 ] ] ]) 267 | // ┌─ 4 268 | // ┌─ 3 269 | // ┌─ 2 270 | // │ └─ 1 271 | 272 | let tree = treeBefore.insert(4) 273 | it("it matches expected shape") { 274 | expect(tree).to(equal(treeAfter)) 275 | } 276 | } 277 | context("adding a left child to a left-heavy node") { 278 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ [ 2 ], 3 ], 4 ]) 279 | // ┌─ 4 280 | // │ └─ 3 281 | // │ └─ 2 282 | 283 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ [ 1 ], 2 ], 3, [ 4 ] ]) 284 | // ┌─ 4 285 | // ┌─ 3 286 | // │ └─ 2 287 | // │ └─ 1 288 | 289 | let tree = treeBefore.insert(1) 290 | it("it matches expected shape") { 291 | expect(tree).to(equal(treeAfter)) 292 | } 293 | } 294 | context("adding an existing element") { 295 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 296 | // ┌─ 297 | 298 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 299 | // ┌─ 1 300 | 301 | let tree = treeBefore.insert(1) 302 | it("it remains unchanged") { 303 | expect(tree).to(equal(treeAfter)) 304 | } 305 | } 306 | } 307 | } 308 | 309 | func describe_remove() { 310 | typealias Tree = AVLTree 311 | describe("Calling remove()") { 312 | context("on an empty tree") { 313 | let treeBefore = AVLTreeTests.assembleAVLTree([ ]) 314 | // ┌─ 315 | 316 | let treeAfter = AVLTreeTests.assembleAVLTree([ ]) 317 | // ┌─ 318 | 319 | let tree = treeBefore.remove(1) 320 | it("it remains unchanged") { 321 | expect(tree).to(equal(treeAfter)) 322 | } 323 | } 324 | context("for a missing element") { 325 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1 ]) 326 | // ┌─ 1 327 | 328 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1 ]) 329 | // ┌─ 1 330 | 331 | let tree = treeBefore.remove(2) 332 | it("it remains unchanged") { 333 | expect(tree).to(equal(treeAfter)) 334 | } 335 | } 336 | context("for a tree's root element") { 337 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2 ] ]) 338 | // ┌─ 2 339 | // ┌─ 1 340 | 341 | let treeAfter = AVLTreeTests.assembleAVLTree([ 2 ]) 342 | // ┌─ 2 343 | 344 | let tree = treeBefore.remove(1) 345 | it("it matches expected shape") { 346 | expect(tree).to(equal(treeAfter)) 347 | } 348 | } 349 | context("for a tree's leaf element") { 350 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2 ] ]) 351 | // ┌─ 2 352 | // ┌─ 1 353 | 354 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1 ]) 355 | // ┌─ 1 356 | 357 | let tree = treeBefore.remove(2) 358 | it("it matches expected shape") { 359 | expect(tree).to(equal(treeAfter)) 360 | } 361 | } 362 | context("for a tree's branch with one child") { 363 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ [ 3 ], 4 ] ]) 364 | // ┌─ 4 365 | // │ └─ 3 366 | // ┌─ 2 367 | // │ └─ 1 368 | 369 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 370 | // ┌─ 3 371 | // ┌─ 2 372 | // │ └─ 1 373 | 374 | let tree = treeBefore.remove(4) 375 | it("it matches expected shape") { 376 | expect(tree).to(equal(treeAfter)) 377 | } 378 | } 379 | context("for a tree's branch with two children") { 380 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ [ 3 ], 4, [ 5 ] ] ]) 381 | // ┌─ 5 382 | // ┌─ 4 383 | // │ └─ 3 384 | // ┌─ 2 385 | // │ └─ 1 386 | 387 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3, [ 5 ] ] ]) 388 | // ┌─ 5 389 | // ┌─ 3 390 | // ┌─ 2 391 | // │ └─ 1 392 | 393 | let tree = treeBefore.remove(4) 394 | it("it matches expected shape") { 395 | expect(tree).to(equal(treeAfter)) 396 | } 397 | } 398 | } 399 | } 400 | } -------------------------------------------------------------------------------- /ForestTests/BinaryTreeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinaryTreeTests.swift 3 | // ForestTests 4 | // 5 | // Created by Vincent Esche on 2/4/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | import Forest 13 | 14 | class BinaryTreeTests: QuickSpec { 15 | 16 | static func assembleBinaryTree(array: [NSObject]) -> BinaryTree { 17 | typealias Tree = BinaryTree 18 | let tree: Tree 19 | switch array.count { 20 | case 1: 21 | let element = array[0] as! Int 22 | tree = Tree(Tree(), element, Tree()) 23 | case 2: 24 | if array[0] is Int { 25 | let element = array[0] as! Int 26 | let right = assembleBinaryTree(array[1] as! [NSObject]) 27 | tree = Tree(Tree(), element, right) 28 | } else { 29 | let left = assembleBinaryTree(array[0] as! [NSObject]) 30 | let element = array[1] as! Int 31 | tree = Tree(left, element, Tree()) 32 | } 33 | case 3: 34 | let left = assembleBinaryTree(array[0] as! [NSObject]) 35 | let element = array[1] as! Int 36 | let right = assembleBinaryTree(array[2] as! [NSObject]) 37 | tree = Tree(left, element, right) 38 | default: 39 | tree = Tree() 40 | } 41 | return tree 42 | } 43 | 44 | override func spec() { 45 | self.describe_creatingWithNil() 46 | self.describe_creatingWithNilElementNil() 47 | self.describe_creatingWithChildElementNil() 48 | self.describe_creatingWithNilElementChild() 49 | self.describe_creatingWithChildElementChild() 50 | } 51 | 52 | func describe_creatingWithNil() { 53 | typealias Tree = BinaryTree 54 | describe("Creating BinaryTree of pattern") { 55 | context("(nil)") { 56 | let testTree = BinaryTreeTests.assembleBinaryTree([ ]) 57 | // ┌─ 58 | let tree = Tree() 59 | it("it matches expected shape") { 60 | expect(tree).to(equal(testTree)) 61 | } 62 | it("its element is nil") { 63 | expect(tree.element).to(beNil()) 64 | } 65 | it("its left is nil") { 66 | expect(tree.left).to(beNil()) 67 | } 68 | it("its right is nil") { 69 | expect(tree.right).to(beNil()) 70 | } 71 | it("its height is 0") { 72 | expect(tree.height).to(equal(0)) 73 | } 74 | it("its count is 0") { 75 | expect(tree.count).to(equal(0)) 76 | } 77 | } 78 | } 79 | } 80 | 81 | func describe_creatingWithNilElementNil() { 82 | typealias Tree = BinaryTree 83 | describe("Creating BinaryTree of pattern") { 84 | context("(nil, element, nil)") { 85 | let testTree = BinaryTreeTests.assembleBinaryTree([ 1 ]) 86 | // ┌─ 1 87 | 88 | let tree = Tree(1) 89 | it("it matches expected shape") { 90 | expect(tree).to(equal(testTree)) 91 | } 92 | it("its element is nil") { 93 | expect(tree.element).to(equal(1)) 94 | } 95 | it("its left is nil") { 96 | expect(tree.left).to(beNil()) 97 | } 98 | it("its right is nil") { 99 | expect(tree.right).to(beNil()) 100 | } 101 | it("its height is 0") { 102 | expect(tree.height).to(equal(1)) 103 | } 104 | it("its count is 1") { 105 | expect(tree.count).to(equal(1)) 106 | } 107 | } 108 | } 109 | } 110 | 111 | func describe_creatingWithChildElementNil() { 112 | typealias Tree = BinaryTree 113 | describe("Creating BinaryTree of pattern") { 114 | context("(child, element, nil)") { 115 | let testTree = BinaryTreeTests.assembleBinaryTree([ [ 1 ], 2 ]) 116 | // ┌─ 2 117 | // │ └─ 1 118 | 119 | let tree = Tree(Tree(1), 2, Tree()) 120 | it("it matches expected shape") { 121 | expect(tree).to(equal(testTree)) 122 | } 123 | it("its element is nil") { 124 | expect(tree.element).to(equal(2)) 125 | } 126 | it("its left is not nil") { 127 | expect(tree.left).toNot(beNil()) 128 | } 129 | it("its right is nil") { 130 | expect(tree.right).to(beNil()) 131 | } 132 | it("its height is 0") { 133 | expect(tree.height).to(equal(2)) 134 | } 135 | it("its count is 2") { 136 | expect(tree.count).to(equal(2)) 137 | } 138 | } 139 | } 140 | } 141 | 142 | func describe_creatingWithNilElementChild() { 143 | typealias Tree = BinaryTree 144 | describe("Creating BinaryTree of pattern") { 145 | context("(nil, element, child)") { 146 | let testTree = BinaryTreeTests.assembleBinaryTree([ 1, [ 2 ] ]) 147 | // ┌─ 2 148 | // ┌─ 1 149 | 150 | let tree = Tree(Tree(), 1, Tree(2)) 151 | it("it matches expected shape") { 152 | expect(tree).to(equal(testTree)) 153 | } 154 | it("its element is nil") { 155 | expect(tree.element).to(equal(1)) 156 | } 157 | it("its left is nil") { 158 | expect(tree.left).to(beNil()) 159 | } 160 | it("its right is not nil") { 161 | expect(tree.right).toNot(beNil()) 162 | } 163 | it("its height is 0") { 164 | expect(tree.height).to(equal(2)) 165 | } 166 | it("its count is 2") { 167 | expect(tree.count).to(equal(2)) 168 | } 169 | } 170 | } 171 | } 172 | 173 | func describe_creatingWithChildElementChild() { 174 | typealias Tree = BinaryTree 175 | describe("Creating BinaryTree of pattern") { 176 | context("(child, element, child)") { 177 | let testTree = BinaryTreeTests.assembleBinaryTree([ [ 1 ], 2, [ 3 ] ]) 178 | // ┌─ 3 179 | // ┌─ 2 180 | // │ └─ 1 181 | 182 | let tree = Tree(Tree(1), 2, Tree(3)) 183 | it("it matches expected shape") { 184 | expect(tree).to(equal(testTree)) 185 | } 186 | it("its element is nil") { 187 | expect(tree.element).to(equal(2)) 188 | } 189 | it("its left is not nil") { 190 | expect(tree.left).toNot(beNil()) 191 | } 192 | it("its right is not nil") { 193 | expect(tree.right).toNot(beNil()) 194 | } 195 | it("its height is 0") { 196 | expect(tree.height).to(equal(2)) 197 | } 198 | it("its count is 3") { 199 | expect(tree.count).to(equal(3)) 200 | } 201 | } 202 | } 203 | } 204 | } -------------------------------------------------------------------------------- /ForestTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ForestTests/RBTreeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RBTreeTests.swift 3 | // ForestTests 4 | // 5 | // Created by Vincent Esche on 2/4/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | import Forest 13 | 14 | class RBTreeTests: BinaryTreeTests { 15 | 16 | static func assembleRBTree(array: [NSObject]) -> RBTree { 17 | typealias Tree = RBTree 18 | switch assembleRBTreeSubTree(array) { 19 | case let .Branch(l, e, r, _): 20 | return Tree(l, e, r, .Black) 21 | case .Leaf: 22 | return .Leaf 23 | } 24 | } 25 | 26 | static func assembleRBTreeSubTree(array: [NSObject]) -> RBTree { 27 | typealias Tree = RBTree 28 | 29 | let tree: Tree 30 | switch array.count { 31 | case 1: 32 | let element = array[0] as! Int 33 | tree = Tree(Tree(), element, Tree(), .Red) 34 | case 2: 35 | if array[0] is Int { 36 | let element = array[0] as! Int 37 | let right = assembleRBTreeSubTree(array[1] as! [NSObject]) 38 | tree = Tree(Tree(), element, right, .Red) 39 | } else { 40 | let left = assembleRBTreeSubTree(array[0] as! [NSObject]) 41 | let element = array[1] as! Int 42 | tree = Tree(left, element, Tree(), .Red) 43 | } 44 | case 3: 45 | let left = assembleRBTreeSubTree(array[0] as! [NSObject]) 46 | let element = array[1] as! Int 47 | let right = assembleRBTreeSubTree(array[2] as! [NSObject]) 48 | tree = Tree(left, element, right, .Red) 49 | default: 50 | tree = Tree() 51 | } 52 | return tree 53 | } 54 | 55 | override func spec() { 56 | super.spec() 57 | 58 | self.describe_creatingWithSequence() 59 | self.describe_noRotation() 60 | self.describe_leftRotation() 61 | self.describe_rightRotation() 62 | self.describe_leftRightRotation() 63 | self.describe_rightLeftRotation() 64 | self.describe_insert() 65 | self.describe_remove() 66 | self.describe_isValid() 67 | } 68 | 69 | func describe_creatingWithSequence() { 70 | typealias Tree = RBTree 71 | describe("Creating RBTree") { 72 | context("from sequence") { 73 | let testTree = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3, [ [ 4 ], 5 ] ]) 74 | // ┌─ 5 75 | // │ └─ 4 76 | // ┌─ 3 77 | // │ └─ 2 78 | // │ └─ 1 79 | 80 | let tree = Tree(sequence: [1, 2, 3, 4, 5]) 81 | 82 | it("it matches expected shape") { 83 | expect(tree).to(equal(testTree)) 84 | } 85 | it("it is valid") { 86 | expect(tree.isValid()).to(beTrue()) 87 | } 88 | } 89 | } 90 | } 91 | 92 | func describe_noRotation() { 93 | typealias Tree = RBTree 94 | describe("Calling rebalance()") { 95 | context("on a balanced tree") { 96 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 97 | // ┌─ 3 98 | // ┌─ 2 99 | // │ └─ 1 100 | 101 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 102 | // ┌─ 3 103 | // ┌─ 2 104 | // │ └─ 1 105 | 106 | let tree = treeBefore.rebalance() 107 | it("it remains unchanged") { 108 | expect(tree).to(equal(treeAfter)) 109 | } 110 | } 111 | } 112 | } 113 | 114 | func describe_leftRotation() { 115 | typealias Tree = RBTree 116 | describe("Calling rebalance()") { 117 | context("on an unbalanced right-right-heavy tree") { 118 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2, [ 3 ] ] ]) 119 | // ┌─ 3 120 | // ┌─ 2 121 | // ┌─ 1 122 | 123 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 124 | // ┌─ 3 125 | // ┌─ 2 126 | // │ └─ 1 127 | 128 | let tree = treeBefore.rebalance() 129 | it("it matches expected (balanced) shape") { 130 | expect(tree).to(equal(treeAfter)) 131 | } 132 | } 133 | } 134 | } 135 | 136 | func describe_rightRotation() { 137 | typealias Tree = RBTree 138 | describe("Calling rebalance()") { 139 | context("on an unbalanced left-left-heavy tree") { 140 | let treeBefore = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3 ]) 141 | // ┌─ 3 142 | // │ └─ 2 143 | // │ └─ 1 144 | 145 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 146 | // ┌─ 3 147 | // ┌─ 2 148 | // │ └─ 1 149 | 150 | let tree = treeBefore.rebalance() 151 | it("it matches expected (balanced) shape") { 152 | expect(tree).to(equal(treeAfter)) 153 | } 154 | } 155 | } 156 | } 157 | 158 | func describe_leftRightRotation() { 159 | typealias Tree = RBTree 160 | describe("Calling rebalance()") { 161 | context("on an unbalanced left-right-heavy tree") { 162 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1, [ 2 ] ], 3 ]) 163 | // ┌─ 3 164 | // │ │ ┌─ 2 165 | // │ └─ 1 166 | 167 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 168 | // ┌─ 3 169 | // ┌─ 2 170 | // │ └─ 1 171 | 172 | let tree = treeBefore.rebalance() 173 | it("it matches expected (balanced) shape") { 174 | expect(tree).to(equal(treeAfter)) 175 | } 176 | } 177 | } 178 | } 179 | 180 | func describe_rightLeftRotation() { 181 | typealias Tree = RBTree 182 | describe("Calling rebalance()") { 183 | context("on an unbalanced left-right-heavy tree") { 184 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ [ 2 ], 3 ] ]) 185 | // ┌─ 3 186 | // │ └─ 2 187 | // ┌─ 1 188 | 189 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 190 | // ┌─ 3 191 | // ┌─ 2 192 | // │ └─ 1 193 | 194 | let tree = treeBefore.rebalance() 195 | it("it matches expected (balanced) shape") { 196 | expect(tree).to(equal(treeAfter)) 197 | } 198 | } 199 | } 200 | } 201 | 202 | func describe_insert() { 203 | typealias Tree = RBTree 204 | describe("Calling insert()") { 205 | context("on an empty tree") { 206 | let treeBefore = RBTreeTests.assembleRBTree([ ]) 207 | // ┌─ 208 | 209 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 210 | // ┌─ 1 211 | 212 | let tree = treeBefore.insert(1) 213 | it("it matches expected shape") { 214 | expect(tree).to(equal(treeAfter)) 215 | } 216 | } 217 | context("on a root-only tree") { 218 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 219 | // ┌─ 1 220 | 221 | let treeAfter = RBTreeTests.assembleRBTree([ 1, [ 2 ] ]) 222 | // ┌─ 2 223 | // ┌─ 1 224 | 225 | let tree = treeBefore.insert(2) 226 | it("it matches expected shape") { 227 | expect(tree).to(equal(treeAfter)) 228 | } 229 | } 230 | context("adding a right child to a left-heavy node") { 231 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2 ]) 232 | // ┌─ 2 233 | // │ └─ 1 234 | 235 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 236 | // ┌─ 3 237 | // ┌─ 2 238 | // │ └─ 1 239 | 240 | let tree = treeBefore.insert(3) 241 | it("it matches expected shape") { 242 | expect(tree).to(equal(treeAfter)) 243 | } 244 | } 245 | context("adding a left child to a right-heavy node") { 246 | let treeBefore = RBTreeTests.assembleRBTree([ 2, [ 3 ] ]) 247 | // ┌─ 3 248 | // ┌─ 2 249 | 250 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 251 | // ┌─ 3 252 | // ┌─ 2 253 | // │ └─ 1 254 | 255 | let tree = treeBefore.insert(1) 256 | it("it matches expected shape") { 257 | expect(tree).to(equal(treeAfter)) 258 | } 259 | } 260 | context("adding a right child to a right-heavy node") { 261 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2 ]) 262 | // ┌─ 2 263 | // │ └─ 1 264 | 265 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 266 | // ┌─ 3 267 | // ┌─ 2 268 | // │ └─ 1 269 | 270 | let tree = treeBefore.insert(3) 271 | it("it matches expected shape") { 272 | expect(tree).to(equal(treeAfter)) 273 | } 274 | } 275 | context("adding a right child to a right-heavy node") { 276 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2 , [ 3 ] ] ]) 277 | // ┌─ 3 278 | // ┌─ 2 279 | // ┌─ 1 280 | 281 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3, [ 4 ] ] ]) 282 | // ┌─ 4 283 | // ┌─ 3 284 | // ┌─ 2 285 | // │ └─ 1 286 | 287 | let tree = treeBefore.insert(4) 288 | it("it matches expected shape") { 289 | expect(tree).to(equal(treeAfter)) 290 | } 291 | } 292 | context("adding a left child to a left-heavy node") { 293 | let treeBefore = RBTreeTests.assembleRBTree([ [ [ 2 ], 3 ], 4 ]) 294 | // ┌─ 4 295 | // │ └─ 3 296 | // │ └─ 2 297 | 298 | let treeAfter = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3, [ 4 ] ]) 299 | // ┌─ 4 300 | // ┌─ 3 301 | // │ └─ 2 302 | // │ └─ 1 303 | 304 | let tree = treeBefore.insert(1) 305 | it("it matches expected shape") { 306 | expect(tree).to(equal(treeAfter)) 307 | } 308 | } 309 | context("adding an existing element") { 310 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 311 | // ┌─ 312 | 313 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 314 | // ┌─ 1 315 | 316 | let tree = treeBefore.insert(1) 317 | it("it remains unchanged") { 318 | expect(tree).to(equal(treeAfter)) 319 | } 320 | } 321 | } 322 | } 323 | 324 | func describe_remove() { 325 | typealias Tree = RBTree 326 | describe("Calling remove()") { 327 | context("on an empty tree") { 328 | let treeBefore = RBTreeTests.assembleRBTree([ ]) 329 | // ┌─ 330 | 331 | let treeAfter = RBTreeTests.assembleRBTree([ ]) 332 | // ┌─ 333 | 334 | let tree = treeBefore.remove(1) 335 | it("it remains unchanged") { 336 | expect(tree).to(equal(treeAfter)) 337 | } 338 | } 339 | context("for a missing element") { 340 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 341 | // ┌─ 1 342 | 343 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 344 | // ┌─ 1 345 | 346 | let tree = treeBefore.remove(2) 347 | it("it remains unchanged") { 348 | expect(tree).to(equal(treeAfter)) 349 | } 350 | } 351 | context("for a tree's root element") { 352 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2 ] ]) 353 | // ┌─ 2 354 | // ┌─ 1 355 | 356 | let treeAfter = RBTreeTests.assembleRBTree([ 2 ]) 357 | // ┌─ 2 358 | 359 | let tree = treeBefore.remove(1) 360 | it("it matches expected shape") { 361 | expect(tree).to(equal(treeAfter)) 362 | } 363 | } 364 | context("for a tree's leaf element") { 365 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2 ] ]) 366 | // ┌─ 2 367 | // ┌─ 1 368 | 369 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 370 | // ┌─ 1 371 | 372 | let tree = treeBefore.remove(2) 373 | it("it matches expected shape") { 374 | expect(tree).to(equal(treeAfter)) 375 | } 376 | } 377 | context("for a tree's branch with one child") { 378 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ [ 3 ], 4 ] ]) 379 | // ┌─ 4 380 | // │ └─ 3 381 | // ┌─ 2 382 | // │ └─ 1 383 | 384 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 385 | // ┌─ 3 386 | // ┌─ 2 387 | // │ └─ 1 388 | 389 | let tree = treeBefore.remove(4) 390 | it("it matches expected shape") { 391 | expect(tree).to(equal(treeAfter)) 392 | } 393 | } 394 | context("for a tree's branch with two children") { 395 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ [ 3 ], 4, [ 5 ] ] ]) 396 | // ┌─ 5 397 | // ┌─ 4 398 | // │ └─ 3 399 | // ┌─ 2 400 | // │ └─ 1 401 | 402 | let treeAfter = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3, [ 5 ] ]) 403 | // ┌─ 5 404 | // ┌─ 3 405 | // │ └─ 2 406 | // │ └─ 1 407 | 408 | let tree = treeBefore.remove(4) 409 | it("it matches expected shape") { 410 | expect(tree).to(equal(treeAfter)) 411 | } 412 | } 413 | } 414 | } 415 | 416 | func describe_isValid() { 417 | typealias Tree = RBTree 418 | describe("Calling isValid()") { 419 | context("on a valid tree") { 420 | let rrr = Tree(Tree(), 15, Tree(), .Red) 421 | let lrl = Tree(Tree(), 4, Tree(), .Red) 422 | 423 | let rl = Tree(Tree(), 8, Tree(), .Black) 424 | let rr = Tree(Tree(), 14, rrr, .Black) 425 | 426 | let ll = Tree(Tree(), 1, Tree(), .Black) 427 | let lr = Tree(lrl, 5, Tree(), .Black) 428 | 429 | let l = Tree(ll, 2, lr, .Red) 430 | let r = Tree(rl, 11, rr, .Red) 431 | 432 | let tree = Tree(l, 7, r, .Black) 433 | 434 | it("it returns true") { 435 | expect(tree.isValid()).to(beTrue()) 436 | } 437 | } 438 | context("on an invalid tree") { 439 | let lrll = Tree(Tree(), 4, Tree(), .Black) 440 | 441 | let lrl = Tree(lrll, 5, Tree(), .Red) 442 | let lrr = Tree(Tree(), 8, Tree(), .Red) 443 | 444 | let ll = Tree(Tree(), 1, Tree(), .Black) 445 | let lr = Tree(lrl, 7, lrr, .Black) 446 | 447 | let rr = Tree(Tree(), 15, Tree(), .Red) 448 | 449 | let l = Tree(ll, 2, lr, .Red) 450 | let r = Tree(Tree(), 14, rr, .Black) 451 | 452 | let tree = Tree(l, 11, r, .Black) 453 | // debugPrint(tree) 454 | 455 | it("it returns false") { 456 | expect(tree.isValid()).to(beFalse()) 457 | } 458 | } 459 | } 460 | } 461 | 462 | } -------------------------------------------------------------------------------- /Icon.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/Icon.sketch -------------------------------------------------------------------------------- /Jumbotron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/regexident/Forest/22a45c0ce3736d32f5e217ae94c625a2ce1bc88d/Jumbotron.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Vincent Esche 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | 4. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes code by Vincent Esche." where would be replaced by the name of the specific source-code package being made use of. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name: "Forest" 5 | ) 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Logo](Jumbotron.png) 2 | 3 | # Forest 4 | 5 | **Forest**, just like any other, is a collection of trees. What else were you expecting? 6 | 7 | ## Binary Trees 8 | 9 | ### `BinaryTree`, a [persistent][1] [binary tree](https://en.wikipedia.org/wiki/Binary_tree) 10 | 11 | A minimalist implementation of a binary tree using `indirect enum`. 12 | 13 | ## Binary Search Trees 14 | 15 | ### `AVLTree`, a [persistent][1] [AVL-Tree](https://en.wikipedia.org/wiki/AVL_tree) 16 | 17 | ### `RBTree`, a [persistent][1] [Red-Black-Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) 18 | 19 | ## Benchmarks 20 | 21 | **Forest** contains a benchmarks app. 22 | 23 | ## Installation 24 | 25 | Just copy the files in `"Forest/Classes/..."` into your project. 26 | 27 | Alternatively you can install **Forest** into your project with [Carthage][2] (`github 'regexident/Forest'`) or with [CocoaPods][3] (`pod 'Forest'`) 28 | 29 | ## Swift 30 | 31 | **Forest** is implemented in 100% Swift. 32 | 33 | ## Creator 34 | 35 | Vincent Esche ([@regexident][4]) 36 | 37 | ## License 38 | 39 | **Forest** is available under a **modified BSD-3 clause license** with the **additional requirement of attribution**. See the `LICENSE` file for more info. 40 | 41 | [1]: https://en.wikipedia.org/wiki/Persistent_data_structure 42 | [2]: https://github.com/Carthage/Carthage 43 | [3]: http://cocoapods.org/ 44 | [4]: http://twitter.com/regexident 45 | -------------------------------------------------------------------------------- /Sources/BinarySearchTrees/AVLTree.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVLTree.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 2/12/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public enum AVLTree: MutableBinarySearchTreeType { 10 | 11 | public typealias Element = E 12 | 13 | case leaf 14 | indirect case branch(AVLTree, Element, AVLTree, Int8) 15 | 16 | public var height: Int8 { 17 | return extendedAnalysis(branch: { _, _, _, h in h }, leaf: { 0 }) 18 | } 19 | 20 | public init() { 21 | self = .leaf 22 | } 23 | 24 | public init(_ element: Element) { 25 | self.init(.leaf, element, .leaf) 26 | } 27 | 28 | public init(_ left: AVLTree, _ element: Element, _ right: AVLTree) { 29 | let height = Swift.max(left.height, right.height) + 1 30 | self = .branch(left, element, right, height) 31 | } 32 | 33 | public init(sortedSequence: S) where S.Iterator.Element == Element { 34 | self = AVLTree(sortedArraySlice: ArraySlice(sortedSequence)) 35 | } 36 | 37 | fileprivate init(sortedArraySlice slice: ArraySlice) { 38 | let range = slice.startIndex.. (AVLTree, Element?) { 49 | return analysis(branch: { l, e, r in 50 | if element < e { 51 | let (subtree, inserted) = l.insertAndReturnExisting(element) 52 | return (AVLTree(subtree, e, r).rebalance(), inserted) 53 | } else if element > e { 54 | let (subtree, inserted) = r.insertAndReturnExisting(element) 55 | return (AVLTree(l, e, subtree).rebalance(), inserted) 56 | } else { 57 | return (AVLTree(l, element, r), e) 58 | } 59 | }, leaf: { 60 | (AVLTree(.leaf, element, .leaf), nil) 61 | }) 62 | } 63 | 64 | public func removeAndReturnExisting(_ element: Element) -> (AVLTree, Element?) { 65 | return analysis(branch: { l, e, r in 66 | if element < e { 67 | let (subtree, removed) = l.removeAndReturnExisting(element) 68 | return (AVLTree(subtree, e, r).rebalance(), removed) 69 | } else if element > e { 70 | let (subtree, removed) = r.removeAndReturnExisting(element) 71 | return (AVLTree(l, e, subtree).rebalance(), removed) 72 | } else { 73 | return self.remove() 74 | } 75 | }, leaf: { 76 | (self, nil) 77 | }) 78 | } 79 | 80 | public func remove() -> (AVLTree, Element?) { 81 | switch self { 82 | case .leaf: 83 | return (self, nil) 84 | case let .branch(.leaf, e, .leaf, _): 85 | return (.leaf, e) 86 | case let .branch(.leaf, e, r, _): 87 | return (r, e) 88 | case let .branch(l, e, .leaf, _): 89 | return (l, e) 90 | case let .branch(l, e, r, _): 91 | let leftMax = l.rightmostBranch() 92 | let subtree = l.remove(leftMax.element!) 93 | return (AVLTree(subtree, leftMax.element!, r), e) 94 | } 95 | } 96 | 97 | public func rebalance(_ tolerance: Int = 1) -> AVLTree { 98 | let t = tolerance // inbalance tolerance 99 | switch self { 100 | case let .branch(.branch(.branch(ll, le, lr, llh), e, rl, lh), re, rr, _) 101 | where (lh > rr.height + t) && (llh > rl.height + t): 102 | // right rotation: 103 | return AVLTree(AVLTree(ll, le, lr), e, AVLTree(rl, re, rr)) 104 | case let .branch(ll, le, .branch(lr, e, .branch(rl, re, rr, rrh), rh), _) 105 | where (rh > ll.height + t) && (rrh > lr.height + t): 106 | // left rotation: 107 | return AVLTree(AVLTree(ll, le, lr), e, AVLTree(rl, re, rr)) 108 | case let .branch(.branch(ll, le, .branch(lr, e, rl, lrh), lh), re, rr, _) 109 | where (lh > rr.height + t) && (lrh > ll.height + t): 110 | // right left rotation: 111 | return AVLTree(AVLTree(ll, le, lr), e, AVLTree(rl, re, rr)) 112 | case let .branch(ll, le, .branch(.branch(lr, e, rl, rlh), re, rr, rh), _) 113 | where (rh > ll.height + t) && (rlh > rr.height + t): 114 | // left right rotation: 115 | return AVLTree(AVLTree(ll, le, lr), e, AVLTree(rl, re, rr)) 116 | default: 117 | return self 118 | } 119 | } 120 | 121 | public func analysis(branch: (AVLTree, Element, AVLTree) -> U, leaf: () -> U) -> U { 122 | switch self { 123 | case let .branch(l, e, r, _): 124 | return branch(l, e, r) 125 | case .leaf: 126 | return leaf() 127 | } 128 | } 129 | 130 | public func extendedAnalysis(branch: (AVLTree, Element, AVLTree, Int8) -> U, leaf: () -> U) -> U { 131 | switch self { 132 | case let .branch(l, e, r, h): 133 | return branch(l, e, r, h) 134 | case .leaf: 135 | return leaf() 136 | } 137 | } 138 | } 139 | 140 | extension AVLTree { 141 | public var debugDescription: String { 142 | return self.recursiveDescription { 143 | return $0.analysis(branch: { _, e, _ in 144 | "\(e) @ \(self.height)" 145 | }, leaf: { 146 | "nil @ \(self.height)" 147 | }) 148 | } 149 | } 150 | } 151 | 152 | extension AVLTree { 153 | public static func ==(lhs: AVLTree, rhs: AVLTree) -> Bool { 154 | switch (lhs, rhs) { 155 | case let (.branch(l1, e1, r1, h1), .branch(l2, e2, r2, h2)): 156 | return (h1 == h2) && (e1 == e2) && (l1 == l2) && (r1 == r2) 157 | case (.leaf, .leaf): 158 | return true 159 | default: 160 | return false 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Sources/BinarySearchTrees/BinarySearchTreeType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinarySearchTreeType.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 7/26/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public enum BinaryTreeStepType { 10 | case root 11 | case leftBranch 12 | case rightBranch 13 | } 14 | 15 | public protocol BinarySearchTreeType : BinaryTreeType, ExpressibleByArrayLiteral { 16 | associatedtype Element: Comparable 17 | 18 | init(sortedSequence: S) where S.Iterator.Element == Element 19 | } 20 | 21 | extension BinarySearchTreeType { 22 | public init(sequence: S) where S.Iterator.Element == Element { 23 | self.init(sortedSequence: sequence.sorted()) 24 | } 25 | 26 | public init(arrayLiteral elements: Element...) { 27 | self.init(sequence: elements) 28 | } 29 | 30 | final public mutating func clearInPlace() { 31 | self = self.clear() 32 | } 33 | 34 | final public func get(_ element: Element) -> Element? { 35 | return analysis(branch: { l, e, r in 36 | if element < e { 37 | return l.get(element) 38 | } else if element > e { 39 | return r.get(element) 40 | } else { 41 | return e 42 | } 43 | }, leaf: { 44 | nil 45 | }) 46 | } 47 | 48 | final public func contains(_ element: Element) -> Bool { 49 | return self.get(element) != nil 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/BinarySearchTrees/GrowableBinarySearchTreeType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GrowableBinarySearchTreeType.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 7/26/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public protocol GrowableBinarySearchTreeType : BinarySearchTreeType { 10 | func insertAndReturnExisting(_ element: Element) -> (Self, Element?) 11 | } 12 | 13 | extension GrowableBinarySearchTreeType { 14 | final public func insert(_ element: Element) -> Self { 15 | return self.insertAndReturnExisting(element).0 16 | } 17 | 18 | final public mutating func insertInPlace(_ element: Element) -> Element? { 19 | let insertedElement: Element? 20 | (self, insertedElement) = self.insertAndReturnExisting(element) 21 | return insertedElement 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/BinarySearchTrees/MutableBinarySearchTreeType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrunableBinarySearchTreeType.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 7/26/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public protocol MutableBinarySearchTreeType : GrowableBinarySearchTreeType, PrunableBinarySearchTreeType { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Sources/BinarySearchTrees/PrunableBinarySearchTreeType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrunableBinarySearchTreeType.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 7/26/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public protocol PrunableBinarySearchTreeType : BinarySearchTreeType { 10 | func removeAndReturnExisting(_ element: Element) -> (Self, Element?) 11 | } 12 | 13 | extension PrunableBinarySearchTreeType { 14 | final public func remove(_ element: Element) -> Self { 15 | return self.removeAndReturnExisting(element).0 16 | } 17 | 18 | final public mutating func removeInPlace(_ element: Element) -> Element? { 19 | let removedElement: Element? 20 | (self, removedElement) = self.removeAndReturnExisting(element) 21 | return removedElement 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/BinarySearchTrees/RBTree.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RBTree.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 2/4/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public enum RBTreeColor { 10 | case red, black 11 | } 12 | 13 | public enum RBTree: MutableBinarySearchTreeType { 14 | 15 | public typealias Element = E 16 | 17 | case leaf 18 | indirect case branch(RBTree, Element, RBTree, RBTreeColor) 19 | 20 | public var color: RBTreeColor { 21 | return extendedAnalysis(branch: { _, _, _, color in color }, leaf: { .black }) 22 | } 23 | 24 | public init() { 25 | self = .leaf 26 | } 27 | 28 | public init(_ element: Element) { 29 | self.init(.leaf, element, .leaf, .red) 30 | } 31 | 32 | public init(_ left: RBTree, _ element: Element, _ right: RBTree, _ color: RBTreeColor) { 33 | self = .branch(left, element, right, color) 34 | } 35 | 36 | public init(sortedSequence: S) where S.Iterator.Element == Element { 37 | self = RBTree(sortedArraySlice: ArraySlice(sortedSequence), color: .black) 38 | } 39 | 40 | fileprivate init(sortedArraySlice slice: ArraySlice, color: RBTreeColor) { 41 | let range = slice.startIndex.. greater.count) ? .red : .black 44 | let rightColor: RBTreeColor = (less.count < greater.count) ? .red : .black 45 | let left = (less.isEmpty) ? RBTree() : RBTree(sortedArraySlice: slice[less], color: leftColor) 46 | let right = (greater.isEmpty) ? RBTree() : RBTree(sortedArraySlice: slice[greater], color: rightColor) 47 | self = RBTree(left, slice[index], right, color) 48 | } else { 49 | self = RBTree() 50 | } 51 | } 52 | 53 | public func insertAndReturnExisting(_ element: Element) -> (RBTree, Element?) { 54 | switch self.insertInSubtreeAndReturnExisting(element) { 55 | case (let .branch(l, e, r, _), let existing): 56 | return (RBTree(l, e, r, .black), existing) 57 | case (let tree, let existing): 58 | return (tree, existing) 59 | } 60 | } 61 | 62 | fileprivate func insertInSubtreeAndReturnExisting(_ element: Element) -> (RBTree, Element?) { 63 | return extendedAnalysis(branch: { l, e, r, c in 64 | if element < e { 65 | let (subtree, inserted) = l.insertInSubtreeAndReturnExisting(element) 66 | return (RBTree(subtree, e, r, c).rebalance(), inserted) 67 | } else if element > e { 68 | let (subtree, inserted) = r.insertInSubtreeAndReturnExisting(element) 69 | return (RBTree(l, e, subtree, c).rebalance(), inserted) 70 | } else { 71 | return (RBTree(l, element, r, c), e) 72 | } 73 | }, leaf: { 74 | (RBTree(.leaf, element, .leaf, .red), nil) 75 | }) 76 | } 77 | 78 | public func removeAndReturnExisting(_ element: Element) -> (RBTree, Element?) { 79 | let (tree, existing) = self.removeFromSubtreeAndReturnExisting(element) 80 | switch tree { 81 | case let .branch(l, e, r, _): 82 | return (RBTree(l, e, r, .black), existing) 83 | default: 84 | return (tree, existing) 85 | } 86 | } 87 | 88 | fileprivate func removeFromSubtreeAndReturnExisting(_ element: Element) -> (RBTree, Element?) { 89 | return extendedAnalysis(branch: { l, e, r, c in 90 | if element < e { 91 | let (subtree, removed) = l.removeFromSubtreeAndReturnExisting(element) 92 | return (RBTree(subtree, e, r, c).rebalance(), removed) 93 | } else if element > e { 94 | let (subtree, removed) = r.removeFromSubtreeAndReturnExisting(element) 95 | return (RBTree(l, e, subtree, c).rebalance(), removed) 96 | } else { 97 | return self.remove() 98 | } 99 | }, leaf: { 100 | (self, nil) 101 | }) 102 | } 103 | 104 | public func remove() -> (RBTree, Element?) { 105 | switch self { 106 | case .leaf: 107 | return (self, nil) 108 | case let .branch(.leaf, e, .leaf, _): 109 | return (.leaf, e) 110 | case let .branch(.leaf, e, r, _): 111 | return (r, e) 112 | case let .branch(l, e, .leaf, _): 113 | return (l, e) 114 | case let .branch(l, e, r, c): 115 | let leftMax = l.rightmostBranch() 116 | let subtree = l.remove(leftMax.element!) 117 | return (RBTree(subtree, leftMax.element!, r, c), e) 118 | } 119 | } 120 | 121 | public func rebalance() -> RBTree { 122 | switch self { 123 | case let .branch(.branch(.branch(ll, le, lr, .red), e, rl, .red), re, rr, .black): 124 | // right rotation: 125 | return .branch(.branch(ll, le, lr, .black), e, .branch(rl, re, rr, .black), .red) 126 | case let .branch(ll, le, .branch(lr, e, .branch(rl, re, rr, .red), .red), .black): 127 | // left rotation: 128 | return .branch(.branch(ll, le, lr, .black), e, .branch(rl, re, rr, .black), .red) 129 | case let .branch(.branch(ll, le, .branch(lr, e, rl, .red), .red), re, rr, .black): 130 | // right left rotation: 131 | return .branch(.branch(ll, le, lr, .black), e, .branch(rl, re, rr, .black), .red) 132 | case let .branch(ll, le, .branch(.branch(lr, e, rl, .red), re, rr, .red), .black): 133 | // left right rotation: 134 | return .branch(.branch(ll, le, lr, .black), e, .branch(rl, re, rr, .black), .red) 135 | default: 136 | return self 137 | } 138 | } 139 | 140 | public func isValid() -> Bool { 141 | return extendedAnalysis(branch: { _, _, _, color in 142 | return (color == .black) && self.checkSubtree().0 143 | }, leaf: { 144 | return true 145 | }) 146 | } 147 | 148 | public func checkSubtree() -> (Bool, Int) { 149 | switch self { 150 | case .branch(.branch(_, _, _, .red), _, .branch(_, _, _, .red), .red): 151 | print("Invalid: A red node must have black children.") 152 | return (false, -1) 153 | case let .branch(l, e, r, c): 154 | let blackCount = (c == .black) ? 1 : 0 155 | let (leftValid, leftBlackCount) = l.checkSubtree() 156 | let (rightValid, rightBlackCount) = r.checkSubtree() 157 | if !leftValid || !rightValid || (leftBlackCount != rightBlackCount) { 158 | return (false, -1) 159 | } 160 | if let le = l.element, let re = r.element, le >= e && re <= e { 161 | print("Invalid: Elements not ordered.") 162 | return (false, -1) 163 | } 164 | return (leftBlackCount == rightBlackCount, blackCount + rightBlackCount) 165 | case .leaf: 166 | return (true, 1) 167 | } 168 | } 169 | 170 | public func analysis(branch: (RBTree, Element, RBTree) -> U, leaf: () -> U) -> U { 171 | switch self { 172 | case let .branch(l, e, r, _): 173 | return branch(l, e, r) 174 | case .leaf: 175 | return leaf() 176 | } 177 | } 178 | 179 | public func extendedAnalysis(branch: (RBTree, Element, RBTree, RBTreeColor) -> U, leaf: () -> U) -> U { 180 | switch self { 181 | case let .branch(l, e, r, c): 182 | return branch(l, e, r, c) 183 | case .leaf: 184 | return leaf() 185 | } 186 | } 187 | } 188 | 189 | extension RBTree { 190 | public var debugDescription: String { 191 | return self.recursiveDescription { 192 | return $0.extendedAnalysis(branch: { _, e, _, c in 193 | let color = (c == .red) ? "red" : "black" 194 | return "\(e) (\(color))" 195 | }, leaf: { 196 | "nil (black)" 197 | }) 198 | } 199 | } 200 | } 201 | 202 | extension RBTree { 203 | public static func ==(lhs: RBTree, rhs: RBTree) -> Bool { 204 | switch (lhs, rhs) { 205 | case let (.branch(l1, e1, r1, _), .branch(l2, e2, r2, _)): 206 | return (e1 == e2) && (l1 == l2) && (r1 == r2) 207 | case (.leaf, .leaf): 208 | return true 209 | default: 210 | return false 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /Sources/BinaryTrees/BinaryTree.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinaryTree.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 2/12/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public enum BinaryTree: BinaryTreeType { 10 | public typealias Element = E 11 | 12 | case leaf 13 | indirect case branch(BinaryTree, Element, BinaryTree) 14 | 15 | public init() { 16 | self = .leaf 17 | } 18 | 19 | public init(_ element: Element) { 20 | self.init(.leaf, element, .leaf) 21 | } 22 | 23 | public init(_ left: BinaryTree, _ element: Element, _ right: BinaryTree) { 24 | self = .branch(left, element, right) 25 | } 26 | 27 | public func analysis(branch: (BinaryTree, Element, BinaryTree) -> U, leaf: () -> U) -> U { 28 | switch self { 29 | case .leaf: 30 | return leaf() 31 | case let .branch(left, element, right): 32 | return branch(left, element, right) 33 | } 34 | } 35 | } 36 | 37 | extension BinaryTree : Equatable { 38 | public static func ==(lhs: BinaryTree, rhs: BinaryTree) -> Bool { 39 | switch (lhs, rhs) { 40 | case let (.branch(l1, e1, r1), .branch(l2, e2, r2)): 41 | return (e1 == e2) && (l1 == l2) && (r1 == r2) 42 | case (.leaf, .leaf): 43 | return true 44 | default: 45 | return false 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/BinaryTrees/BinaryTreeType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinaryTreeType.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 2/12/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | public protocol BinaryTreeType : CustomStringConvertible, CustomDebugStringConvertible, Equatable { 10 | associatedtype Element 11 | 12 | init() 13 | 14 | func analysis(branch: (Self, Element, Self) -> U, leaf: () -> U) -> U 15 | } 16 | 17 | extension BinaryTreeType { 18 | final public var element: Element? { 19 | return analysis(branch: { _, element, _ in 20 | element 21 | }, leaf: { 22 | nil 23 | }) 24 | } 25 | 26 | final public var left: Self? { 27 | return analysis(branch: { left, _, _ in 28 | return (left.isNil) ? nil : left 29 | }, leaf: { 30 | nil 31 | }) 32 | } 33 | 34 | final public var right: Self? { 35 | return analysis(branch: { _, _, right in 36 | return (right.isNil) ? nil : right 37 | }, leaf: { 38 | nil 39 | }) 40 | } 41 | 42 | final public func preorder(_ closure: (Element) -> ()) { 43 | self.analysis(branch: { (l, e, r) -> () in 44 | closure(e) 45 | l.preorder(closure) 46 | r.preorder(closure) 47 | }, leaf: {}) 48 | } 49 | 50 | final public func inorder(_ closure: (Element) -> ()) { 51 | self.analysis(branch: { (l, e, r) -> () in 52 | l.inorder(closure) 53 | closure(e) 54 | r.inorder(closure) 55 | }, leaf: {}) 56 | } 57 | 58 | final public func postorder(_ closure: (Element) -> ()) { 59 | self.analysis(branch: { (l, e, r) -> () in 60 | l.postorder(closure) 61 | r.postorder(closure) 62 | closure(e) 63 | }, leaf: {}) 64 | } 65 | 66 | final public var height: Int8 { 67 | return analysis(branch: { l, _, r in 68 | Swift.max(l.height, r.height) + 1 69 | }, leaf: { 70 | 0 71 | }) 72 | } 73 | 74 | final public var subtreeHeights: (Int, Int) { 75 | return analysis(branch: { l, _, r in 76 | (Int(r.height), Int(l.height)) 77 | }, leaf: { 78 | (0, 0) 79 | }) 80 | } 81 | 82 | final public var balance: Int { 83 | return analysis(branch: { l, _, r in 84 | r.height - l.height 85 | }, leaf: { 86 | 0 87 | }) 88 | } 89 | 90 | final public var count: Int { 91 | return analysis(branch: { l, _, r in 92 | l.count + 1 + r.count 93 | }, leaf: { 94 | 0 95 | }) 96 | } 97 | 98 | final public var isEmpty: Bool { 99 | return self.isNil 100 | } 101 | 102 | final public var isNil: Bool { 103 | return analysis(branch: { _, _, _ in 104 | false 105 | }, leaf: { 106 | true 107 | }) 108 | } 109 | 110 | final func clear() -> Self { 111 | return Self() 112 | } 113 | 114 | final public func generate() -> AnyIterator { 115 | var stack: [Self] = [self] 116 | return AnyIterator { _ -> Element? in 117 | var current = stack.removeLast() 118 | while true { 119 | if current.isNil { 120 | if stack.isEmpty { 121 | return nil 122 | } else { 123 | current = stack.removeLast() 124 | return current.analysis(branch: { _, e, r in 125 | stack.append(r) 126 | return e 127 | }, leaf: { nil }) 128 | } 129 | } else { 130 | current.analysis(branch: { l, _, _ in 131 | stack.append(current) 132 | current = l 133 | return 134 | }, leaf: { return }) 135 | } 136 | } 137 | } 138 | } 139 | 140 | final public func traverseLeftwards(_ closure: (Self) -> ()) -> Self { 141 | closure(self) 142 | return analysis(branch: { l, _, _ in 143 | l.traverseLeftwards(closure) 144 | }, leaf: { 145 | self 146 | }) 147 | } 148 | 149 | final public func traverseRightwards(_ closure: (Self) -> ()) -> Self { 150 | closure(self) 151 | return analysis(branch: { _, _, r in 152 | r.traverseRightwards(closure) 153 | }, leaf: { 154 | self 155 | }) 156 | } 157 | 158 | final public func leftmostBranch() -> Self { 159 | var node = self 160 | let _ = traverseLeftwards { 161 | if !$0.isNil { 162 | node = $0 163 | } 164 | } 165 | return node 166 | } 167 | 168 | final public func rightmostBranch() -> Self { 169 | var node = self 170 | let _ = traverseRightwards { 171 | if !$0.isNil { 172 | node = $0 173 | } 174 | } 175 | return node 176 | } 177 | 178 | final public func recursiveDescription(_ closure: @escaping (Self) -> String?) -> String { 179 | return self.recursiveDescription("", flag: false, closure: closure) 180 | } 181 | 182 | final fileprivate func recursiveDescription(_ string: String, flag: Bool, closure: @escaping (Self) -> String?) -> String { 183 | var recursiveDescription : ((Self, String, Bool) -> String)! = nil 184 | recursiveDescription = { node, prefix, isTail in 185 | var string = "" 186 | if let element = closure(node) { 187 | if let right = node.right, right.analysis(branch: { _, _, _ in true }, leaf: { closure(right) != nil }) { 188 | string += recursiveDescription(right, prefix + ((isTail) ? "│ " : " "), false) 189 | } 190 | string += prefix + ((isTail) ? "└─ " : "┌─ ") + "\(element)\n" 191 | if let left = node.left, left.analysis(branch: { _, _, _ in true }, leaf: { closure(left) != nil }) { 192 | string += recursiveDescription(left, prefix + ((isTail) ? " " : "│ "), true) 193 | } 194 | } 195 | return string 196 | } 197 | return recursiveDescription(self, "", false) 198 | } 199 | 200 | final public var description: String { 201 | return self.recursiveDescription { return $0.analysis(branch: { _, e, _ in "\(e)" }, leaf: { nil }) } 202 | } 203 | 204 | final public var debugDescription: String { 205 | return self.recursiveDescription { return $0.analysis(branch: { _, e, _ in "\(e)" }, leaf: { "nil" }) } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /Sources/CountableRange+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CountableRange.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 9/10/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | extension CountableRange { 10 | func bisect() -> (CountableRange, Index, CountableRange)? { 11 | let count = self.distance(from: self.startIndex, to: self.endIndex) 12 | if count < 1 { 13 | return nil 14 | } 15 | let index = self.index(self.startIndex, offsetBy: count / 2) 16 | let lower = self.startIndex.. AVLTree { 17 | typealias Tree = AVLTree 18 | 19 | let tree: Tree 20 | switch array.count { 21 | case 1: 22 | let element = array[0] as! Int 23 | tree = Tree(Tree(), element, Tree()) 24 | case 2: 25 | if array[0] is Int { 26 | let element = array[0] as! Int 27 | let right = assembleAVLTree(array[1] as! [Any]) 28 | tree = Tree(Tree(), element, right) 29 | } else { 30 | let left = assembleAVLTree(array[0] as! [Any]) 31 | let element = array[1] as! Int 32 | tree = Tree(left, element, Tree()) 33 | } 34 | case 3: 35 | let left = assembleAVLTree(array[0] as! [Any]) 36 | let element = array[1] as! Int 37 | let right = assembleAVLTree(array[2] as! [Any]) 38 | tree = Tree(left, element, right) 39 | default: 40 | tree = Tree() 41 | } 42 | return tree 43 | } 44 | 45 | override func spec() { 46 | super.spec() 47 | 48 | self.describe_creatingWithSequence() 49 | self.describe_noRotation() 50 | self.describe_leftRotation() 51 | self.describe_rightRotation() 52 | self.describe_leftRightRotation() 53 | self.describe_rightLeftRotation() 54 | self.describe_insert() 55 | self.describe_remove() 56 | } 57 | 58 | func describe_creatingWithSequence() { 59 | typealias Tree = AVLTree 60 | describe("Creating AVLTree") { 61 | context("from sequence") { 62 | let testTree = AVLTreeTests.assembleAVLTree([ [ [ 1], 2 ], 3, [ [ 4 ], 5 ] ]) 63 | // ┌─ 5 64 | // │ └─ 4 65 | // ┌─ 3 66 | // │ └─ 2 67 | // │ └─ 1 68 | 69 | let tree = Tree(sequence: [1, 2, 3, 4, 5]) 70 | it("it matches expected shape") { 71 | expect(tree).to(equal(testTree)) 72 | } 73 | } 74 | } 75 | } 76 | 77 | func describe_noRotation() { 78 | typealias Tree = AVLTree 79 | describe("Calling rebalance()") { 80 | context("on a balanced tree") { 81 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 82 | // ┌─ 3 83 | // ┌─ 2 84 | // │ └─ 1 85 | 86 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 87 | // ┌─ 3 88 | // ┌─ 2 89 | // │ └─ 1 90 | 91 | let tree = treeBefore.rebalance(0) 92 | it("it remains unchanged") { 93 | expect(tree).to(equal(treeAfter)) 94 | } 95 | } 96 | } 97 | } 98 | 99 | func describe_leftRotation() { 100 | typealias Tree = AVLTree 101 | describe("Calling rebalance()") { 102 | context("on an unbalanced right-right-heavy tree") { 103 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2, [ 3 ] ] ]) 104 | // ┌─ 3 105 | // ┌─ 2 106 | // ┌─ 1 107 | 108 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 109 | // ┌─ 3 110 | // ┌─ 2 111 | // │ └─ 1 112 | 113 | let tree = treeBefore.rebalance(0) 114 | it("it matches expected (balanced) shape") { 115 | expect(tree).to(equal(treeAfter)) 116 | } 117 | } 118 | } 119 | } 120 | 121 | func describe_rightRotation() { 122 | typealias Tree = AVLTree 123 | describe("Calling rebalance()") { 124 | context("on an unbalanced left-left-heavy tree") { 125 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ [ 1 ], 2 ], 3 ]) 126 | // ┌─ 3 127 | // │ └─ 2 128 | // │ └─ 1 129 | 130 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 131 | // ┌─ 3 132 | // ┌─ 2 133 | // │ └─ 1 134 | 135 | let tree = treeBefore.rebalance(0) 136 | it("it matches expected (balanced) shape") { 137 | expect(tree).to(equal(treeAfter)) 138 | } 139 | } 140 | } 141 | } 142 | 143 | func describe_leftRightRotation() { 144 | typealias Tree = AVLTree 145 | describe("Calling rebalance()") { 146 | context("on an unbalanced left-right-heavy tree") { 147 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1, [ 2 ] ], 3 ]) 148 | // ┌─ 3 149 | // │ │ ┌─ 2 150 | // │ └─ 1 151 | 152 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 153 | // ┌─ 3 154 | // ┌─ 2 155 | // │ └─ 1 156 | 157 | let tree = treeBefore.rebalance(0) 158 | it("it matches expected (balanced) shape") { 159 | expect(tree).to(equal(treeAfter)) 160 | } 161 | } 162 | } 163 | } 164 | 165 | func describe_rightLeftRotation() { 166 | typealias Tree = AVLTree 167 | describe("Calling rebalance()") { 168 | context("on an unbalanced left-right-heavy tree") { 169 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ [ 2 ], 3 ] ]) 170 | // ┌─ 3 171 | // │ └─ 2 172 | // ┌─ 1 173 | 174 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 175 | // ┌─ 3 176 | // ┌─ 2 177 | // │ └─ 1 178 | 179 | let tree = treeBefore.rebalance(0) 180 | it("it matches expected (balanced) shape") { 181 | expect(tree).to(equal(treeAfter)) 182 | } 183 | } 184 | } 185 | } 186 | 187 | func describe_insert() { 188 | typealias Tree = AVLTree 189 | describe("Calling insert()") { 190 | context("on an empty tree") { 191 | let treeBefore = AVLTreeTests.assembleAVLTree([ ]) 192 | // ┌─ 193 | 194 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1 ]) 195 | // ┌─ 1 196 | 197 | let tree = treeBefore.insert(1) 198 | it("it matches expected shape") { 199 | expect(tree).to(equal(treeAfter)) 200 | } 201 | } 202 | context("on a root-only tree") { 203 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1 ]) 204 | // ┌─ 1 205 | 206 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1, [ 2 ] ]) 207 | // ┌─ 2 208 | // ┌─ 1 209 | 210 | let tree = treeBefore.insert(2) 211 | it("it matches expected shape") { 212 | expect(tree).to(equal(treeAfter)) 213 | } 214 | } 215 | context("adding a right child to a left-heavy node") { 216 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2 ]) 217 | // ┌─ 2 218 | // │ └─ 1 219 | 220 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 221 | // ┌─ 3 222 | // ┌─ 2 223 | // │ └─ 1 224 | 225 | let tree = treeBefore.insert(3) 226 | it("it matches expected shape") { 227 | expect(tree).to(equal(treeAfter)) 228 | } 229 | } 230 | context("adding a left child to a right-heavy node") { 231 | let treeBefore = AVLTreeTests.assembleAVLTree([ 2, [ 3 ] ]) 232 | // ┌─ 3 233 | // ┌─ 2 234 | 235 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 236 | // ┌─ 3 237 | // ┌─ 2 238 | // │ └─ 1 239 | 240 | let tree = treeBefore.insert(1) 241 | it("it matches expected shape") { 242 | expect(tree).to(equal(treeAfter)) 243 | } 244 | } 245 | context("adding a right child to a right-heavy node") { 246 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2 ]) 247 | // ┌─ 2 248 | // │ └─ 1 249 | 250 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 251 | // ┌─ 3 252 | // ┌─ 2 253 | // │ └─ 1 254 | 255 | let tree = treeBefore.insert(3) 256 | it("it matches expected shape") { 257 | expect(tree).to(equal(treeAfter)) 258 | } 259 | } 260 | context("adding a right child to a right-heavy node") { 261 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2 , [ 3 ] ] ]) 262 | // ┌─ 3 263 | // ┌─ 2 264 | // ┌─ 1 265 | 266 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3, [ 4 ] ] ]) 267 | // ┌─ 4 268 | // ┌─ 3 269 | // ┌─ 2 270 | // │ └─ 1 271 | 272 | let tree = treeBefore.insert(4) 273 | it("it matches expected shape") { 274 | expect(tree).to(equal(treeAfter)) 275 | } 276 | } 277 | context("adding a left child to a left-heavy node") { 278 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ [ 2 ], 3 ], 4 ]) 279 | // ┌─ 4 280 | // │ └─ 3 281 | // │ └─ 2 282 | 283 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ [ 1 ], 2 ], 3, [ 4 ] ]) 284 | // ┌─ 4 285 | // ┌─ 3 286 | // │ └─ 2 287 | // │ └─ 1 288 | 289 | let tree = treeBefore.insert(1) 290 | it("it matches expected shape") { 291 | expect(tree).to(equal(treeAfter)) 292 | } 293 | } 294 | context("adding an existing element") { 295 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 296 | // ┌─ 297 | 298 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 299 | // ┌─ 1 300 | 301 | let tree = treeBefore.insert(1) 302 | it("it remains unchanged") { 303 | expect(tree).to(equal(treeAfter)) 304 | } 305 | } 306 | } 307 | } 308 | 309 | func describe_remove() { 310 | typealias Tree = AVLTree 311 | describe("Calling remove()") { 312 | context("on an empty tree") { 313 | let treeBefore = AVLTreeTests.assembleAVLTree([ ]) 314 | // ┌─ 315 | 316 | let treeAfter = AVLTreeTests.assembleAVLTree([ ]) 317 | // ┌─ 318 | 319 | let tree = treeBefore.remove(1) 320 | it("it remains unchanged") { 321 | expect(tree).to(equal(treeAfter)) 322 | } 323 | } 324 | context("for a missing element") { 325 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1 ]) 326 | // ┌─ 1 327 | 328 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1 ]) 329 | // ┌─ 1 330 | 331 | let tree = treeBefore.remove(2) 332 | it("it remains unchanged") { 333 | expect(tree).to(equal(treeAfter)) 334 | } 335 | } 336 | context("for a tree's root element") { 337 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2 ] ]) 338 | // ┌─ 2 339 | // ┌─ 1 340 | 341 | let treeAfter = AVLTreeTests.assembleAVLTree([ 2 ]) 342 | // ┌─ 2 343 | 344 | let tree = treeBefore.remove(1) 345 | it("it matches expected shape") { 346 | expect(tree).to(equal(treeAfter)) 347 | } 348 | } 349 | context("for a tree's leaf element") { 350 | let treeBefore = AVLTreeTests.assembleAVLTree([ 1, [ 2 ] ]) 351 | // ┌─ 2 352 | // ┌─ 1 353 | 354 | let treeAfter = AVLTreeTests.assembleAVLTree([ 1 ]) 355 | // ┌─ 1 356 | 357 | let tree = treeBefore.remove(2) 358 | it("it matches expected shape") { 359 | expect(tree).to(equal(treeAfter)) 360 | } 361 | } 362 | context("for a tree's branch with one child") { 363 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ [ 3 ], 4 ] ]) 364 | // ┌─ 4 365 | // │ └─ 3 366 | // ┌─ 2 367 | // │ └─ 1 368 | 369 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3 ] ]) 370 | // ┌─ 3 371 | // ┌─ 2 372 | // │ └─ 1 373 | 374 | let tree = treeBefore.remove(4) 375 | it("it matches expected shape") { 376 | expect(tree).to(equal(treeAfter)) 377 | } 378 | } 379 | context("for a tree's branch with two children") { 380 | let treeBefore = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ [ 3 ], 4, [ 5 ] ] ]) 381 | // ┌─ 5 382 | // ┌─ 4 383 | // │ └─ 3 384 | // ┌─ 2 385 | // │ └─ 1 386 | 387 | let treeAfter = AVLTreeTests.assembleAVLTree([ [ 1 ], 2, [ 3, [ 5 ] ] ]) 388 | // ┌─ 5 389 | // ┌─ 3 390 | // ┌─ 2 391 | // │ └─ 1 392 | 393 | let tree = treeBefore.remove(4) 394 | it("it matches expected shape") { 395 | expect(tree).to(equal(treeAfter)) 396 | } 397 | } 398 | } 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /Tests/Forest/BinaryTreeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinaryTreeTests.swift 3 | // ForestTests 4 | // 5 | // Created by Vincent Esche on 2/4/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | import Forest 13 | 14 | class BinaryTreeTests: QuickSpec { 15 | 16 | static func assembleBinaryTree(_ array: [Any]) -> BinaryTree { 17 | typealias Tree = BinaryTree 18 | let tree: Tree 19 | switch array.count { 20 | case 1: 21 | let element = array[0] as! Int 22 | tree = Tree(Tree(), element, Tree()) 23 | case 2: 24 | if array[0] is Int { 25 | let element = array[0] as! Int 26 | let right = assembleBinaryTree(array[1] as! [Any]) 27 | tree = Tree(Tree(), element, right) 28 | } else { 29 | let left = assembleBinaryTree(array[0] as! [Any]) 30 | let element = array[1] as! Int 31 | tree = Tree(left, element, Tree()) 32 | } 33 | case 3: 34 | let left = assembleBinaryTree(array[0] as! [Any]) 35 | let element = array[1] as! Int 36 | let right = assembleBinaryTree(array[2] as! [Any]) 37 | tree = Tree(left, element, right) 38 | default: 39 | tree = Tree() 40 | } 41 | return tree 42 | } 43 | 44 | override func spec() { 45 | self.describe_creatingWithNil() 46 | self.describe_creatingWithNilElementNil() 47 | self.describe_creatingWithChildElementNil() 48 | self.describe_creatingWithNilElementChild() 49 | self.describe_creatingWithChildElementChild() 50 | } 51 | 52 | func describe_creatingWithNil() { 53 | typealias Tree = BinaryTree 54 | describe("Creating BinaryTree of pattern") { 55 | context("(nil)") { 56 | let testTree = BinaryTreeTests.assembleBinaryTree([ ]) 57 | // ┌─ 58 | let tree = Tree() 59 | it("it matches expected shape") { 60 | expect(tree).to(equal(testTree)) 61 | } 62 | it("its element is nil") { 63 | expect(tree.element).to(beNil()) 64 | } 65 | it("its left is nil") { 66 | expect(tree.left).to(beNil()) 67 | } 68 | it("its right is nil") { 69 | expect(tree.right).to(beNil()) 70 | } 71 | it("its height is 0") { 72 | expect(tree.height).to(equal(0)) 73 | } 74 | it("its count is 0") { 75 | expect(tree.count).to(equal(0)) 76 | } 77 | } 78 | } 79 | } 80 | 81 | func describe_creatingWithNilElementNil() { 82 | typealias Tree = BinaryTree 83 | describe("Creating BinaryTree of pattern") { 84 | context("(nil, element, nil)") { 85 | let testTree = BinaryTreeTests.assembleBinaryTree([ 1 ]) 86 | // ┌─ 1 87 | 88 | let tree = Tree(1) 89 | it("it matches expected shape") { 90 | expect(tree).to(equal(testTree)) 91 | } 92 | it("its element is nil") { 93 | expect(tree.element).to(equal(1)) 94 | } 95 | it("its left is nil") { 96 | expect(tree.left).to(beNil()) 97 | } 98 | it("its right is nil") { 99 | expect(tree.right).to(beNil()) 100 | } 101 | it("its height is 0") { 102 | expect(tree.height).to(equal(1)) 103 | } 104 | it("its count is 1") { 105 | expect(tree.count).to(equal(1)) 106 | } 107 | } 108 | } 109 | } 110 | 111 | func describe_creatingWithChildElementNil() { 112 | typealias Tree = BinaryTree 113 | describe("Creating BinaryTree of pattern") { 114 | context("(child, element, nil)") { 115 | let testTree = BinaryTreeTests.assembleBinaryTree([ [ 1 ], 2 ]) 116 | // ┌─ 2 117 | // │ └─ 1 118 | 119 | let tree = Tree(Tree(1), 2, Tree()) 120 | it("it matches expected shape") { 121 | expect(tree).to(equal(testTree)) 122 | } 123 | it("its element is nil") { 124 | expect(tree.element).to(equal(2)) 125 | } 126 | it("its left is not nil") { 127 | expect(tree.left).toNot(beNil()) 128 | } 129 | it("its right is nil") { 130 | expect(tree.right).to(beNil()) 131 | } 132 | it("its height is 0") { 133 | expect(tree.height).to(equal(2)) 134 | } 135 | it("its count is 2") { 136 | expect(tree.count).to(equal(2)) 137 | } 138 | } 139 | } 140 | } 141 | 142 | func describe_creatingWithNilElementChild() { 143 | typealias Tree = BinaryTree 144 | describe("Creating BinaryTree of pattern") { 145 | context("(nil, element, child)") { 146 | let testTree = BinaryTreeTests.assembleBinaryTree([ 1, [ 2 ] ]) 147 | // ┌─ 2 148 | // ┌─ 1 149 | 150 | let tree = Tree(Tree(), 1, Tree(2)) 151 | it("it matches expected shape") { 152 | expect(tree).to(equal(testTree)) 153 | } 154 | it("its element is nil") { 155 | expect(tree.element).to(equal(1)) 156 | } 157 | it("its left is nil") { 158 | expect(tree.left).to(beNil()) 159 | } 160 | it("its right is not nil") { 161 | expect(tree.right).toNot(beNil()) 162 | } 163 | it("its height is 0") { 164 | expect(tree.height).to(equal(2)) 165 | } 166 | it("its count is 2") { 167 | expect(tree.count).to(equal(2)) 168 | } 169 | } 170 | } 171 | } 172 | 173 | func describe_creatingWithChildElementChild() { 174 | typealias Tree = BinaryTree 175 | describe("Creating BinaryTree of pattern") { 176 | context("(child, element, child)") { 177 | let testTree = BinaryTreeTests.assembleBinaryTree([ [ 1 ], 2, [ 3 ] ]) 178 | // ┌─ 3 179 | // ┌─ 2 180 | // │ └─ 1 181 | 182 | let tree = Tree(Tree(1), 2, Tree(3)) 183 | it("it matches expected shape") { 184 | expect(tree).to(equal(testTree)) 185 | } 186 | it("its element is nil") { 187 | expect(tree.element).to(equal(2)) 188 | } 189 | it("its left is not nil") { 190 | expect(tree.left).toNot(beNil()) 191 | } 192 | it("its right is not nil") { 193 | expect(tree.right).toNot(beNil()) 194 | } 195 | it("its height is 0") { 196 | expect(tree.height).to(equal(2)) 197 | } 198 | it("its count is 3") { 199 | expect(tree.count).to(equal(3)) 200 | } 201 | } 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /Tests/Forest/ForestTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Forest 3 | 4 | class ForestTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct results. 8 | XCTAssertEqual(Forest().text, "Hello, World!") 9 | } 10 | 11 | 12 | static var allTests : [(String, (ForestTests) -> () throws -> Void)] { 13 | return [ 14 | ("testExample", testExample), 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/Forest/KDTreeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KDTreeTests.swift 3 | // Forest 4 | // 5 | // Created by Vincent Esche on 9/8/15. 6 | // Copyright © 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | import Forest 13 | 14 | class KDTreeTests: BinaryTreeTests { 15 | 16 | override func spec() { 17 | super.spec() 18 | 19 | self.describe_KDTree() 20 | } 21 | 22 | func generatePointCloud(count: Int) -> [KDPoint] { 23 | var points = [KDPoint]() 24 | srand(UInt32(time(nil))) 25 | for _ in 0.. 35 | describe("Creating KDTree") { 36 | context("from empty sequence") { 37 | let points = self.generatePointCloud(1000) 38 | let tree = Tree(sequence: points) 39 | // print("tree:") 40 | // debugPrint(tree) 41 | // let nearest = tree.nearest(KDPoint(x: 0.51, y: 0.49)) 42 | // print("nearest: \(nearest)") 43 | 44 | let rect = KDRect(coordinates: [0.0, 0.0], extents: [0.125, 0.125]) 45 | tree.within(rect) { element in print(element) } 46 | } 47 | } 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /Tests/Forest/RBTreeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RBTreeTests.swift 3 | // ForestTests 4 | // 5 | // Created by Vincent Esche on 2/4/15. 6 | // Copyright (c) 2015 Vincent Esche. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | import Forest 13 | 14 | class RBTreeTests: BinaryTreeTests { 15 | 16 | static func assembleRBTree(_ array: [Any]) -> RBTree { 17 | typealias Tree = RBTree 18 | switch assembleRBTreeSubTree(array) { 19 | case let .branch(l, e, r, _): 20 | return Tree(l, e, r, .black) 21 | case .leaf: 22 | return .leaf 23 | } 24 | } 25 | 26 | static func assembleRBTreeSubTree(_ array: [Any]) -> RBTree { 27 | typealias Tree = RBTree 28 | 29 | let tree: Tree 30 | switch array.count { 31 | case 1: 32 | let element = array[0] as! Int 33 | tree = Tree(Tree(), element, Tree(), .red) 34 | case 2: 35 | if array[0] is Int { 36 | let element = array[0] as! Int 37 | let right = assembleRBTreeSubTree(array[1] as! [Any]) 38 | tree = Tree(Tree(), element, right, .red) 39 | } else { 40 | let left = assembleRBTreeSubTree(array[0] as! [Any]) 41 | let element = array[1] as! Int 42 | tree = Tree(left, element, Tree(), .red) 43 | } 44 | case 3: 45 | let left = assembleRBTreeSubTree(array[0] as! [Any]) 46 | let element = array[1] as! Int 47 | let right = assembleRBTreeSubTree(array[2] as! [Any]) 48 | tree = Tree(left, element, right, .red) 49 | default: 50 | tree = Tree() 51 | } 52 | return tree 53 | } 54 | 55 | override func spec() { 56 | super.spec() 57 | 58 | self.describe_creatingWithSequence() 59 | self.describe_noRotation() 60 | self.describe_leftRotation() 61 | self.describe_rightRotation() 62 | self.describe_leftRightRotation() 63 | self.describe_rightLeftRotation() 64 | self.describe_insert() 65 | self.describe_remove() 66 | self.describe_isValid() 67 | } 68 | 69 | func describe_creatingWithSequence() { 70 | typealias Tree = RBTree 71 | describe("Creating RBTree") { 72 | context("from sequence") { 73 | let testTree = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3, [ [ 4 ], 5 ] ]) 74 | // ┌─ 5 75 | // │ └─ 4 76 | // ┌─ 3 77 | // │ └─ 2 78 | // │ └─ 1 79 | 80 | let tree = Tree(sequence: [1, 2, 3, 4, 5]) 81 | 82 | it("it matches expected shape") { 83 | expect(tree).to(equal(testTree)) 84 | } 85 | it("it is valid") { 86 | expect(tree.isValid()).to(beTrue()) 87 | } 88 | } 89 | } 90 | } 91 | 92 | func describe_noRotation() { 93 | typealias Tree = RBTree 94 | describe("Calling rebalance()") { 95 | context("on a balanced tree") { 96 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 97 | // ┌─ 3 98 | // ┌─ 2 99 | // │ └─ 1 100 | 101 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 102 | // ┌─ 3 103 | // ┌─ 2 104 | // │ └─ 1 105 | 106 | let tree = treeBefore.rebalance() 107 | it("it remains unchanged") { 108 | expect(tree).to(equal(treeAfter)) 109 | } 110 | } 111 | } 112 | } 113 | 114 | func describe_leftRotation() { 115 | typealias Tree = RBTree 116 | describe("Calling rebalance()") { 117 | context("on an unbalanced right-right-heavy tree") { 118 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2, [ 3 ] ] ]) 119 | // ┌─ 3 120 | // ┌─ 2 121 | // ┌─ 1 122 | 123 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 124 | // ┌─ 3 125 | // ┌─ 2 126 | // │ └─ 1 127 | 128 | let tree = treeBefore.rebalance() 129 | it("it matches expected (balanced) shape") { 130 | expect(tree).to(equal(treeAfter)) 131 | } 132 | } 133 | } 134 | } 135 | 136 | func describe_rightRotation() { 137 | typealias Tree = RBTree 138 | describe("Calling rebalance()") { 139 | context("on an unbalanced left-left-heavy tree") { 140 | let treeBefore = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3 ]) 141 | // ┌─ 3 142 | // │ └─ 2 143 | // │ └─ 1 144 | 145 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 146 | // ┌─ 3 147 | // ┌─ 2 148 | // │ └─ 1 149 | 150 | let tree = treeBefore.rebalance() 151 | it("it matches expected (balanced) shape") { 152 | expect(tree).to(equal(treeAfter)) 153 | } 154 | } 155 | } 156 | } 157 | 158 | func describe_leftRightRotation() { 159 | typealias Tree = RBTree 160 | describe("Calling rebalance()") { 161 | context("on an unbalanced left-right-heavy tree") { 162 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1, [ 2 ] ], 3 ]) 163 | // ┌─ 3 164 | // │ │ ┌─ 2 165 | // │ └─ 1 166 | 167 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 168 | // ┌─ 3 169 | // ┌─ 2 170 | // │ └─ 1 171 | 172 | let tree = treeBefore.rebalance() 173 | it("it matches expected (balanced) shape") { 174 | expect(tree).to(equal(treeAfter)) 175 | } 176 | } 177 | } 178 | } 179 | 180 | func describe_rightLeftRotation() { 181 | typealias Tree = RBTree 182 | describe("Calling rebalance()") { 183 | context("on an unbalanced left-right-heavy tree") { 184 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ [ 2 ], 3 ] ]) 185 | // ┌─ 3 186 | // │ └─ 2 187 | // ┌─ 1 188 | 189 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 190 | // ┌─ 3 191 | // ┌─ 2 192 | // │ └─ 1 193 | 194 | let tree = treeBefore.rebalance() 195 | it("it matches expected (balanced) shape") { 196 | expect(tree).to(equal(treeAfter)) 197 | } 198 | } 199 | } 200 | } 201 | 202 | func describe_insert() { 203 | typealias Tree = RBTree 204 | describe("Calling insert()") { 205 | context("on an empty tree") { 206 | let treeBefore = RBTreeTests.assembleRBTree([ ]) 207 | // ┌─ 208 | 209 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 210 | // ┌─ 1 211 | 212 | let tree = treeBefore.insert(1) 213 | it("it matches expected shape") { 214 | expect(tree).to(equal(treeAfter)) 215 | } 216 | } 217 | context("on a root-only tree") { 218 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 219 | // ┌─ 1 220 | 221 | let treeAfter = RBTreeTests.assembleRBTree([ 1, [ 2 ] ]) 222 | // ┌─ 2 223 | // ┌─ 1 224 | 225 | let tree = treeBefore.insert(2) 226 | it("it matches expected shape") { 227 | expect(tree).to(equal(treeAfter)) 228 | } 229 | } 230 | context("adding a right child to a left-heavy node") { 231 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2 ]) 232 | // ┌─ 2 233 | // │ └─ 1 234 | 235 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 236 | // ┌─ 3 237 | // ┌─ 2 238 | // │ └─ 1 239 | 240 | let tree = treeBefore.insert(3) 241 | it("it matches expected shape") { 242 | expect(tree).to(equal(treeAfter)) 243 | } 244 | } 245 | context("adding a left child to a right-heavy node") { 246 | let treeBefore = RBTreeTests.assembleRBTree([ 2, [ 3 ] ]) 247 | // ┌─ 3 248 | // ┌─ 2 249 | 250 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 251 | // ┌─ 3 252 | // ┌─ 2 253 | // │ └─ 1 254 | 255 | let tree = treeBefore.insert(1) 256 | it("it matches expected shape") { 257 | expect(tree).to(equal(treeAfter)) 258 | } 259 | } 260 | context("adding a right child to a right-heavy node") { 261 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2 ]) 262 | // ┌─ 2 263 | // │ └─ 1 264 | 265 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 266 | // ┌─ 3 267 | // ┌─ 2 268 | // │ └─ 1 269 | 270 | let tree = treeBefore.insert(3) 271 | it("it matches expected shape") { 272 | expect(tree).to(equal(treeAfter)) 273 | } 274 | } 275 | context("adding a right child to a right-heavy node") { 276 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2 , [ 3 ] ] ]) 277 | // ┌─ 3 278 | // ┌─ 2 279 | // ┌─ 1 280 | 281 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3, [ 4 ] ] ]) 282 | // ┌─ 4 283 | // ┌─ 3 284 | // ┌─ 2 285 | // │ └─ 1 286 | 287 | let tree = treeBefore.insert(4) 288 | it("it matches expected shape") { 289 | expect(tree).to(equal(treeAfter)) 290 | } 291 | } 292 | context("adding a left child to a left-heavy node") { 293 | let treeBefore = RBTreeTests.assembleRBTree([ [ [ 2 ], 3 ], 4 ]) 294 | // ┌─ 4 295 | // │ └─ 3 296 | // │ └─ 2 297 | 298 | let treeAfter = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3, [ 4 ] ]) 299 | // ┌─ 4 300 | // ┌─ 3 301 | // │ └─ 2 302 | // │ └─ 1 303 | 304 | let tree = treeBefore.insert(1) 305 | it("it matches expected shape") { 306 | expect(tree).to(equal(treeAfter)) 307 | } 308 | } 309 | context("adding an existing element") { 310 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 311 | // ┌─ 312 | 313 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 314 | // ┌─ 1 315 | 316 | let tree = treeBefore.insert(1) 317 | it("it remains unchanged") { 318 | expect(tree).to(equal(treeAfter)) 319 | } 320 | } 321 | } 322 | } 323 | 324 | func describe_remove() { 325 | typealias Tree = RBTree 326 | describe("Calling remove()") { 327 | context("on an empty tree") { 328 | let treeBefore = RBTreeTests.assembleRBTree([ ]) 329 | // ┌─ 330 | 331 | let treeAfter = RBTreeTests.assembleRBTree([ ]) 332 | // ┌─ 333 | 334 | let tree = treeBefore.remove(1) 335 | it("it remains unchanged") { 336 | expect(tree).to(equal(treeAfter)) 337 | } 338 | } 339 | context("for a missing element") { 340 | let treeBefore = RBTreeTests.assembleRBTree([ 1 ]) 341 | // ┌─ 1 342 | 343 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 344 | // ┌─ 1 345 | 346 | let tree = treeBefore.remove(2) 347 | it("it remains unchanged") { 348 | expect(tree).to(equal(treeAfter)) 349 | } 350 | } 351 | context("for a tree's root element") { 352 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2 ] ]) 353 | // ┌─ 2 354 | // ┌─ 1 355 | 356 | let treeAfter = RBTreeTests.assembleRBTree([ 2 ]) 357 | // ┌─ 2 358 | 359 | let tree = treeBefore.remove(1) 360 | it("it matches expected shape") { 361 | expect(tree).to(equal(treeAfter)) 362 | } 363 | } 364 | context("for a tree's leaf element") { 365 | let treeBefore = RBTreeTests.assembleRBTree([ 1, [ 2 ] ]) 366 | // ┌─ 2 367 | // ┌─ 1 368 | 369 | let treeAfter = RBTreeTests.assembleRBTree([ 1 ]) 370 | // ┌─ 1 371 | 372 | let tree = treeBefore.remove(2) 373 | it("it matches expected shape") { 374 | expect(tree).to(equal(treeAfter)) 375 | } 376 | } 377 | context("for a tree's branch with one child") { 378 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ [ 3 ], 4 ] ]) 379 | // ┌─ 4 380 | // │ └─ 3 381 | // ┌─ 2 382 | // │ └─ 1 383 | 384 | let treeAfter = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ 3 ] ]) 385 | // ┌─ 3 386 | // ┌─ 2 387 | // │ └─ 1 388 | 389 | let tree = treeBefore.remove(4) 390 | it("it matches expected shape") { 391 | expect(tree).to(equal(treeAfter)) 392 | } 393 | } 394 | context("for a tree's branch with two children") { 395 | let treeBefore = RBTreeTests.assembleRBTree([ [ 1 ], 2, [ [ 3 ], 4, [ 5 ] ] ]) 396 | // ┌─ 5 397 | // ┌─ 4 398 | // │ └─ 3 399 | // ┌─ 2 400 | // │ └─ 1 401 | 402 | let treeAfter = RBTreeTests.assembleRBTree([ [ [ 1 ], 2 ], 3, [ 5 ] ]) 403 | // ┌─ 5 404 | // ┌─ 3 405 | // │ └─ 2 406 | // │ └─ 1 407 | 408 | let tree = treeBefore.remove(4) 409 | it("it matches expected shape") { 410 | expect(tree).to(equal(treeAfter)) 411 | } 412 | } 413 | } 414 | } 415 | 416 | func describe_isValid() { 417 | typealias Tree = RBTree 418 | describe("Calling isValid()") { 419 | context("on a valid tree") { 420 | let rrr = Tree(Tree(), 15, Tree(), .red) 421 | let lrl = Tree(Tree(), 4, Tree(), .red) 422 | 423 | let rl = Tree(Tree(), 8, Tree(), .black) 424 | let rr = Tree(Tree(), 14, rrr, .black) 425 | 426 | let ll = Tree(Tree(), 1, Tree(), .black) 427 | let lr = Tree(lrl, 5, Tree(), .black) 428 | 429 | let l = Tree(ll, 2, lr, .red) 430 | let r = Tree(rl, 11, rr, .red) 431 | 432 | let tree = Tree(l, 7, r, .black) 433 | 434 | it("it returns true") { 435 | expect(tree.isValid()).to(beTrue()) 436 | } 437 | } 438 | context("on an invalid tree") { 439 | let lrll = Tree(Tree(), 4, Tree(), .black) 440 | 441 | let lrl = Tree(lrll, 5, Tree(), .red) 442 | let lrr = Tree(Tree(), 8, Tree(), .red) 443 | 444 | let ll = Tree(Tree(), 1, Tree(), .black) 445 | let lr = Tree(lrl, 7, lrr, .black) 446 | 447 | let rr = Tree(Tree(), 15, Tree(), .red) 448 | 449 | let l = Tree(ll, 2, lr, .red) 450 | let r = Tree(Tree(), 14, rr, .black) 451 | 452 | let tree = Tree(l, 11, r, .black) 453 | // debugPrint(tree) 454 | 455 | it("it returns false") { 456 | expect(tree.isValid()).to(beFalse()) 457 | } 458 | } 459 | } 460 | } 461 | 462 | } 463 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import ForestTestSuite 3 | 4 | XCTMain([ 5 | testCase(ForestTests.allTests), 6 | ]) 7 | --------------------------------------------------------------------------------