├── .gitignore ├── DifferenceAlgorithmComparison.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcbaselines │ └── 8C9CCD1B201033480055DEFE.xcbaseline │ ├── 40A4F4B4-246F-4A96-90EA-178E6C8DD5C1.plist │ └── Info.plist ├── DifferenceAlgorithmComparison ├── Algorithm │ ├── Heckel.swift │ ├── Myers.swift │ ├── NestedHeckel.swift │ └── Wu.swift ├── AppDelegate.swift ├── Base.lproj │ └── Main.storyboard ├── Info.plist └── ViewController.swift ├── DifferenceAlgorithmComparisonTests ├── HeckelTest.swift ├── Info.plist ├── MyersTest.swift └── WuTest.swift ├── Images ├── EditGraph.png └── EditGraph_k_move.png ├── README.jp.md └── README.md /.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 | ##/.DS_Store 11 | Pods/ 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata/ 23 | 24 | ## Other 25 | *.moved-aside 26 | *.xccheckout 27 | *.xcscmblueprint 28 | 29 | ## Obj-C/Swift specific 30 | *.hmap 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | ## Playgrounds 36 | timeline.xctimeline 37 | playground.xcworkspace 38 | 39 | # Swift Package Manager 40 | # 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | .build/ 45 | 46 | # CocoaPods 47 | # 48 | # We recommend against adding the Pods directory to your .gitignore. However 49 | # you should judge for yourself, the pros and cons are mentioned at: 50 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 51 | # 52 | # Pods/ 53 | 54 | # Carthage 55 | # 56 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 57 | # Carthage/Checkouts 58 | 59 | Carthage/Build 60 | 61 | # fastlane 62 | # 63 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 64 | # screenshots whenever they are needed. 65 | # For more information about the recommended setup visit: 66 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 67 | 68 | fastlane/report.xml 69 | fastlane/Preview.html 70 | fastlane/screenshots 71 | fastlane/test_output 72 | -------------------------------------------------------------------------------- /DifferenceAlgorithmComparison.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8C54D92B20789B0D00964B30 /* Heckel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C54D92720789B0D00964B30 /* Heckel.swift */; }; 11 | 8C54D92C20789B0D00964B30 /* Myers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C54D92820789B0D00964B30 /* Myers.swift */; }; 12 | 8C54D92D20789B0D00964B30 /* NestedHeckel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C54D92920789B0D00964B30 /* NestedHeckel.swift */; }; 13 | 8C54D92E20789B0D00964B30 /* Wu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C54D92A20789B0D00964B30 /* Wu.swift */; }; 14 | 8C9CCD0C201033480055DEFE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9CCD0B201033480055DEFE /* AppDelegate.swift */; }; 15 | 8C9CCD0E201033480055DEFE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9CCD0D201033480055DEFE /* ViewController.swift */; }; 16 | 8C9CCD11201033480055DEFE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C9CCD0F201033480055DEFE /* Main.storyboard */; }; 17 | 8C9CCD2C2010336D0055DEFE /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 8C9CCD2B2010336D0055DEFE /* README.md */; }; 18 | 8C9CCD32201202C60055DEFE /* HeckelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9CCD31201202C60055DEFE /* HeckelTest.swift */; }; 19 | 8CF98E712033286000EE3096 /* MyersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CF98E702033286000EE3096 /* MyersTest.swift */; }; 20 | FABB8F932054CF5500956C11 /* WuTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FABB8F922054CF5500956C11 /* WuTest.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 8C9CCD1D201033480055DEFE /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 8C9CCD00201033480055DEFE /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 8C9CCD07201033480055DEFE; 29 | remoteInfo = DifferenceAlgorithmComparison; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 8C54D92720789B0D00964B30 /* Heckel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Heckel.swift; sourceTree = ""; }; 35 | 8C54D92820789B0D00964B30 /* Myers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Myers.swift; sourceTree = ""; }; 36 | 8C54D92920789B0D00964B30 /* NestedHeckel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NestedHeckel.swift; sourceTree = ""; }; 37 | 8C54D92A20789B0D00964B30 /* Wu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wu.swift; sourceTree = ""; }; 38 | 8C9CCD08201033480055DEFE /* DifferenceAlgorithmComparison.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DifferenceAlgorithmComparison.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 8C9CCD0B201033480055DEFE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 40 | 8C9CCD0D201033480055DEFE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 41 | 8C9CCD10201033480055DEFE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 8C9CCD17201033480055DEFE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | 8C9CCD1C201033480055DEFE /* DifferenceAlgorithmComparisonTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DifferenceAlgorithmComparisonTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 8C9CCD22201033480055DEFE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 8C9CCD2B2010336D0055DEFE /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 46 | 8C9CCD31201202C60055DEFE /* HeckelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeckelTest.swift; sourceTree = ""; }; 47 | 8CF98E702033286000EE3096 /* MyersTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyersTest.swift; sourceTree = ""; }; 48 | FABB8F922054CF5500956C11 /* WuTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WuTest.swift; sourceTree = ""; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 8C9CCD05201033480055DEFE /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | 8C9CCD19201033480055DEFE /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | 8C54D92620789B0D00964B30 /* Algorithm */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 8C54D92720789B0D00964B30 /* Heckel.swift */, 73 | 8C54D92820789B0D00964B30 /* Myers.swift */, 74 | 8C54D92920789B0D00964B30 /* NestedHeckel.swift */, 75 | 8C54D92A20789B0D00964B30 /* Wu.swift */, 76 | ); 77 | path = Algorithm; 78 | sourceTree = ""; 79 | }; 80 | 8C9CCCFF201033480055DEFE = { 81 | isa = PBXGroup; 82 | children = ( 83 | 8C9CCD2B2010336D0055DEFE /* README.md */, 84 | 8C9CCD0A201033480055DEFE /* DifferenceAlgorithmComparison */, 85 | 8C9CCD1F201033480055DEFE /* DifferenceAlgorithmComparisonTests */, 86 | 8C9CCD09201033480055DEFE /* Products */, 87 | ); 88 | sourceTree = ""; 89 | }; 90 | 8C9CCD09201033480055DEFE /* Products */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 8C9CCD08201033480055DEFE /* DifferenceAlgorithmComparison.app */, 94 | 8C9CCD1C201033480055DEFE /* DifferenceAlgorithmComparisonTests.xctest */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | 8C9CCD0A201033480055DEFE /* DifferenceAlgorithmComparison */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 8C54D92620789B0D00964B30 /* Algorithm */, 103 | 8C9CCD0B201033480055DEFE /* AppDelegate.swift */, 104 | 8C9CCD0D201033480055DEFE /* ViewController.swift */, 105 | 8C9CCD0F201033480055DEFE /* Main.storyboard */, 106 | 8C9CCD17201033480055DEFE /* Info.plist */, 107 | ); 108 | path = DifferenceAlgorithmComparison; 109 | sourceTree = ""; 110 | }; 111 | 8C9CCD1F201033480055DEFE /* DifferenceAlgorithmComparisonTests */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 8C9CCD31201202C60055DEFE /* HeckelTest.swift */, 115 | 8C9CCD22201033480055DEFE /* Info.plist */, 116 | 8CF98E702033286000EE3096 /* MyersTest.swift */, 117 | FABB8F922054CF5500956C11 /* WuTest.swift */, 118 | ); 119 | path = DifferenceAlgorithmComparisonTests; 120 | sourceTree = ""; 121 | }; 122 | /* End PBXGroup section */ 123 | 124 | /* Begin PBXNativeTarget section */ 125 | 8C9CCD07201033480055DEFE /* DifferenceAlgorithmComparison */ = { 126 | isa = PBXNativeTarget; 127 | buildConfigurationList = 8C9CCD25201033480055DEFE /* Build configuration list for PBXNativeTarget "DifferenceAlgorithmComparison" */; 128 | buildPhases = ( 129 | 8C9CCD04201033480055DEFE /* Sources */, 130 | 8C9CCD05201033480055DEFE /* Frameworks */, 131 | 8C9CCD06201033480055DEFE /* Resources */, 132 | ); 133 | buildRules = ( 134 | ); 135 | dependencies = ( 136 | ); 137 | name = DifferenceAlgorithmComparison; 138 | productName = DifferenceAlgorithmComparison; 139 | productReference = 8C9CCD08201033480055DEFE /* DifferenceAlgorithmComparison.app */; 140 | productType = "com.apple.product-type.application"; 141 | }; 142 | 8C9CCD1B201033480055DEFE /* DifferenceAlgorithmComparisonTests */ = { 143 | isa = PBXNativeTarget; 144 | buildConfigurationList = 8C9CCD28201033480055DEFE /* Build configuration list for PBXNativeTarget "DifferenceAlgorithmComparisonTests" */; 145 | buildPhases = ( 146 | 8C9CCD18201033480055DEFE /* Sources */, 147 | 8C9CCD19201033480055DEFE /* Frameworks */, 148 | 8C9CCD1A201033480055DEFE /* Resources */, 149 | ); 150 | buildRules = ( 151 | ); 152 | dependencies = ( 153 | 8C9CCD1E201033480055DEFE /* PBXTargetDependency */, 154 | ); 155 | name = DifferenceAlgorithmComparisonTests; 156 | productName = DifferenceAlgorithmComparisonTests; 157 | productReference = 8C9CCD1C201033480055DEFE /* DifferenceAlgorithmComparisonTests.xctest */; 158 | productType = "com.apple.product-type.bundle.unit-test"; 159 | }; 160 | /* End PBXNativeTarget section */ 161 | 162 | /* Begin PBXProject section */ 163 | 8C9CCD00201033480055DEFE /* Project object */ = { 164 | isa = PBXProject; 165 | attributes = { 166 | LastSwiftUpdateCheck = 0920; 167 | LastUpgradeCheck = 0920; 168 | ORGANIZATIONNAME = yuyahorita; 169 | TargetAttributes = { 170 | 8C9CCD07201033480055DEFE = { 171 | CreatedOnToolsVersion = 9.2; 172 | ProvisioningStyle = Automatic; 173 | }; 174 | 8C9CCD1B201033480055DEFE = { 175 | CreatedOnToolsVersion = 9.2; 176 | ProvisioningStyle = Automatic; 177 | TestTargetID = 8C9CCD07201033480055DEFE; 178 | }; 179 | }; 180 | }; 181 | buildConfigurationList = 8C9CCD03201033480055DEFE /* Build configuration list for PBXProject "DifferenceAlgorithmComparison" */; 182 | compatibilityVersion = "Xcode 8.0"; 183 | developmentRegion = en; 184 | hasScannedForEncodings = 0; 185 | knownRegions = ( 186 | en, 187 | Base, 188 | ); 189 | mainGroup = 8C9CCCFF201033480055DEFE; 190 | productRefGroup = 8C9CCD09201033480055DEFE /* Products */; 191 | projectDirPath = ""; 192 | projectRoot = ""; 193 | targets = ( 194 | 8C9CCD07201033480055DEFE /* DifferenceAlgorithmComparison */, 195 | 8C9CCD1B201033480055DEFE /* DifferenceAlgorithmComparisonTests */, 196 | ); 197 | }; 198 | /* End PBXProject section */ 199 | 200 | /* Begin PBXResourcesBuildPhase section */ 201 | 8C9CCD06201033480055DEFE /* Resources */ = { 202 | isa = PBXResourcesBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | 8C9CCD2C2010336D0055DEFE /* README.md in Resources */, 206 | 8C9CCD11201033480055DEFE /* Main.storyboard in Resources */, 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | }; 210 | 8C9CCD1A201033480055DEFE /* Resources */ = { 211 | isa = PBXResourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXResourcesBuildPhase section */ 218 | 219 | /* Begin PBXSourcesBuildPhase section */ 220 | 8C9CCD04201033480055DEFE /* Sources */ = { 221 | isa = PBXSourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | 8C54D92D20789B0D00964B30 /* NestedHeckel.swift in Sources */, 225 | 8C9CCD0E201033480055DEFE /* ViewController.swift in Sources */, 226 | 8C9CCD0C201033480055DEFE /* AppDelegate.swift in Sources */, 227 | 8C54D92C20789B0D00964B30 /* Myers.swift in Sources */, 228 | 8C54D92B20789B0D00964B30 /* Heckel.swift in Sources */, 229 | 8C54D92E20789B0D00964B30 /* Wu.swift in Sources */, 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | 8C9CCD18201033480055DEFE /* Sources */ = { 234 | isa = PBXSourcesBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | 8CF98E712033286000EE3096 /* MyersTest.swift in Sources */, 238 | 8C9CCD32201202C60055DEFE /* HeckelTest.swift in Sources */, 239 | FABB8F932054CF5500956C11 /* WuTest.swift in Sources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | /* End PBXSourcesBuildPhase section */ 244 | 245 | /* Begin PBXTargetDependency section */ 246 | 8C9CCD1E201033480055DEFE /* PBXTargetDependency */ = { 247 | isa = PBXTargetDependency; 248 | target = 8C9CCD07201033480055DEFE /* DifferenceAlgorithmComparison */; 249 | targetProxy = 8C9CCD1D201033480055DEFE /* PBXContainerItemProxy */; 250 | }; 251 | /* End PBXTargetDependency section */ 252 | 253 | /* Begin PBXVariantGroup section */ 254 | 8C9CCD0F201033480055DEFE /* Main.storyboard */ = { 255 | isa = PBXVariantGroup; 256 | children = ( 257 | 8C9CCD10201033480055DEFE /* Base */, 258 | ); 259 | name = Main.storyboard; 260 | sourceTree = ""; 261 | }; 262 | /* End PBXVariantGroup section */ 263 | 264 | /* Begin XCBuildConfiguration section */ 265 | 8C9CCD23201033480055DEFE /* Debug */ = { 266 | isa = XCBuildConfiguration; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | CLANG_ANALYZER_NONNULL = YES; 270 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 271 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 272 | CLANG_CXX_LIBRARY = "libc++"; 273 | CLANG_ENABLE_MODULES = YES; 274 | CLANG_ENABLE_OBJC_ARC = YES; 275 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 276 | CLANG_WARN_BOOL_CONVERSION = YES; 277 | CLANG_WARN_COMMA = YES; 278 | CLANG_WARN_CONSTANT_CONVERSION = YES; 279 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 280 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 281 | CLANG_WARN_EMPTY_BODY = YES; 282 | CLANG_WARN_ENUM_CONVERSION = YES; 283 | CLANG_WARN_INFINITE_RECURSION = YES; 284 | CLANG_WARN_INT_CONVERSION = YES; 285 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 286 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 287 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 288 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 289 | CLANG_WARN_STRICT_PROTOTYPES = YES; 290 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 291 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 292 | CLANG_WARN_UNREACHABLE_CODE = YES; 293 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 294 | CODE_SIGN_IDENTITY = "iPhone Developer"; 295 | COPY_PHASE_STRIP = NO; 296 | DEBUG_INFORMATION_FORMAT = dwarf; 297 | ENABLE_STRICT_OBJC_MSGSEND = YES; 298 | ENABLE_TESTABILITY = YES; 299 | GCC_C_LANGUAGE_STANDARD = gnu11; 300 | GCC_DYNAMIC_NO_PIC = NO; 301 | GCC_NO_COMMON_BLOCKS = YES; 302 | GCC_OPTIMIZATION_LEVEL = 0; 303 | GCC_PREPROCESSOR_DEFINITIONS = ( 304 | "DEBUG=1", 305 | "$(inherited)", 306 | ); 307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 309 | GCC_WARN_UNDECLARED_SELECTOR = YES; 310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 311 | GCC_WARN_UNUSED_FUNCTION = YES; 312 | GCC_WARN_UNUSED_VARIABLE = YES; 313 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 314 | MTL_ENABLE_DEBUG_INFO = YES; 315 | ONLY_ACTIVE_ARCH = YES; 316 | SDKROOT = iphoneos; 317 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 318 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 319 | }; 320 | name = Debug; 321 | }; 322 | 8C9CCD24201033480055DEFE /* Release */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ALWAYS_SEARCH_USER_PATHS = NO; 326 | CLANG_ANALYZER_NONNULL = YES; 327 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 328 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 329 | CLANG_CXX_LIBRARY = "libc++"; 330 | CLANG_ENABLE_MODULES = YES; 331 | CLANG_ENABLE_OBJC_ARC = YES; 332 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 333 | CLANG_WARN_BOOL_CONVERSION = YES; 334 | CLANG_WARN_COMMA = YES; 335 | CLANG_WARN_CONSTANT_CONVERSION = YES; 336 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 337 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 338 | CLANG_WARN_EMPTY_BODY = YES; 339 | CLANG_WARN_ENUM_CONVERSION = YES; 340 | CLANG_WARN_INFINITE_RECURSION = YES; 341 | CLANG_WARN_INT_CONVERSION = YES; 342 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 343 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 344 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 345 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 346 | CLANG_WARN_STRICT_PROTOTYPES = YES; 347 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 348 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 349 | CLANG_WARN_UNREACHABLE_CODE = YES; 350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 351 | CODE_SIGN_IDENTITY = "iPhone Developer"; 352 | COPY_PHASE_STRIP = NO; 353 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 354 | ENABLE_NS_ASSERTIONS = NO; 355 | ENABLE_STRICT_OBJC_MSGSEND = YES; 356 | GCC_C_LANGUAGE_STANDARD = gnu11; 357 | GCC_NO_COMMON_BLOCKS = YES; 358 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 359 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 360 | GCC_WARN_UNDECLARED_SELECTOR = YES; 361 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 362 | GCC_WARN_UNUSED_FUNCTION = YES; 363 | GCC_WARN_UNUSED_VARIABLE = YES; 364 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 365 | MTL_ENABLE_DEBUG_INFO = NO; 366 | SDKROOT = iphoneos; 367 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 368 | VALIDATE_PRODUCT = YES; 369 | }; 370 | name = Release; 371 | }; 372 | 8C9CCD26201033480055DEFE /* Debug */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | CODE_SIGN_STYLE = Automatic; 377 | INFOPLIST_FILE = DifferenceAlgorithmComparison/Info.plist; 378 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 379 | PRODUCT_BUNDLE_IDENTIFIER = yuyahorita.DifferenceAlgorithmComparison; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | SWIFT_VERSION = 4.0; 382 | TARGETED_DEVICE_FAMILY = "1,2"; 383 | }; 384 | name = Debug; 385 | }; 386 | 8C9CCD27201033480055DEFE /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | CODE_SIGN_STYLE = Automatic; 391 | INFOPLIST_FILE = DifferenceAlgorithmComparison/Info.plist; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 393 | PRODUCT_BUNDLE_IDENTIFIER = yuyahorita.DifferenceAlgorithmComparison; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | SWIFT_VERSION = 4.0; 396 | TARGETED_DEVICE_FAMILY = "1,2"; 397 | }; 398 | name = Release; 399 | }; 400 | 8C9CCD29201033480055DEFE /* Debug */ = { 401 | isa = XCBuildConfiguration; 402 | buildSettings = { 403 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 404 | BUNDLE_LOADER = "$(TEST_HOST)"; 405 | CODE_SIGN_STYLE = Automatic; 406 | INFOPLIST_FILE = DifferenceAlgorithmComparisonTests/Info.plist; 407 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 408 | PRODUCT_BUNDLE_IDENTIFIER = yuyahorita.DifferenceAlgorithmComparisonTests; 409 | PRODUCT_NAME = "$(TARGET_NAME)"; 410 | SWIFT_VERSION = 4.0; 411 | TARGETED_DEVICE_FAMILY = "1,2"; 412 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DifferenceAlgorithmComparison.app/DifferenceAlgorithmComparison"; 413 | }; 414 | name = Debug; 415 | }; 416 | 8C9CCD2A201033480055DEFE /* Release */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 420 | BUNDLE_LOADER = "$(TEST_HOST)"; 421 | CODE_SIGN_STYLE = Automatic; 422 | INFOPLIST_FILE = DifferenceAlgorithmComparisonTests/Info.plist; 423 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 424 | PRODUCT_BUNDLE_IDENTIFIER = yuyahorita.DifferenceAlgorithmComparisonTests; 425 | PRODUCT_NAME = "$(TARGET_NAME)"; 426 | SWIFT_VERSION = 4.0; 427 | TARGETED_DEVICE_FAMILY = "1,2"; 428 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DifferenceAlgorithmComparison.app/DifferenceAlgorithmComparison"; 429 | }; 430 | name = Release; 431 | }; 432 | /* End XCBuildConfiguration section */ 433 | 434 | /* Begin XCConfigurationList section */ 435 | 8C9CCD03201033480055DEFE /* Build configuration list for PBXProject "DifferenceAlgorithmComparison" */ = { 436 | isa = XCConfigurationList; 437 | buildConfigurations = ( 438 | 8C9CCD23201033480055DEFE /* Debug */, 439 | 8C9CCD24201033480055DEFE /* Release */, 440 | ); 441 | defaultConfigurationIsVisible = 0; 442 | defaultConfigurationName = Release; 443 | }; 444 | 8C9CCD25201033480055DEFE /* Build configuration list for PBXNativeTarget "DifferenceAlgorithmComparison" */ = { 445 | isa = XCConfigurationList; 446 | buildConfigurations = ( 447 | 8C9CCD26201033480055DEFE /* Debug */, 448 | 8C9CCD27201033480055DEFE /* Release */, 449 | ); 450 | defaultConfigurationIsVisible = 0; 451 | defaultConfigurationName = Release; 452 | }; 453 | 8C9CCD28201033480055DEFE /* Build configuration list for PBXNativeTarget "DifferenceAlgorithmComparisonTests" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | 8C9CCD29201033480055DEFE /* Debug */, 457 | 8C9CCD2A201033480055DEFE /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | /* End XCConfigurationList section */ 463 | }; 464 | rootObject = 8C9CCD00201033480055DEFE /* Project object */; 465 | } 466 | -------------------------------------------------------------------------------- /DifferenceAlgorithmComparison.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DifferenceAlgorithmComparison.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DifferenceAlgorithmComparison.xcodeproj/xcshareddata/xcbaselines/8C9CCD1B201033480055DEFE.xcbaseline/40A4F4B4-246F-4A96-90EA-178E6C8DD5C1.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | classNames 6 | 7 | MyersTest 8 | 9 | testPerformanceOriginalModel() 10 | 11 | com.apple.XCTPerformanceMetric_WallClockTime 12 | 13 | baselineAverage 14 | 0.852 15 | baselineIntegrationDisplayName 16 | Local Baseline 17 | 18 | 19 | testPerformanceSnakeCountModel() 20 | 21 | com.apple.XCTPerformanceMetric_WallClockTime 22 | 23 | baselineAverage 24 | 0.783 25 | baselineIntegrationDisplayName 26 | Local Baseline 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DifferenceAlgorithmComparison.xcodeproj/xcshareddata/xcbaselines/8C9CCD1B201033480055DEFE.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | runDestinationsByUUID 6 | 7 | 40A4F4B4-246F-4A96-90EA-178E6C8DD5C1 8 | 9 | localComputer 10 | 11 | busSpeedInMHz 12 | 100 13 | cpuCount 14 | 1 15 | cpuKind 16 | Intel Core i7 17 | cpuSpeedInMHz 18 | 2200 19 | logicalCPUCoresPerPackage 20 | 8 21 | modelCode 22 | MacBookPro11,4 23 | physicalCPUCoresPerPackage 24 | 4 25 | platformIdentifier 26 | com.apple.platform.macosx 27 | 28 | targetArchitecture 29 | x86_64 30 | targetDevice 31 | 32 | modelCode 33 | iPhone10,5 34 | platformIdentifier 35 | com.apple.platform.iphonesimulator 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /DifferenceAlgorithmComparison/Algorithm/Heckel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // oiginalHeckel.swift 3 | // DifferenceAlgorithmComparison 4 | // 5 | // Created by Yuya Horita on 2018/02/14. 6 | // Copyright © 2018年 yuyahorita. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Difference: Equatable { 12 | case delete(element: E, index: Int) 13 | case insert(element: E, index: Int) 14 | case move(element: E, fromIndex: Int, toIndex: Int) 15 | 16 | static func ==(lhs: Difference, rhs: Difference) -> Bool { 17 | switch (lhs, rhs) { 18 | case let (.delete(le, li), .delete(re, ri)): 19 | return le == re && li == ri 20 | 21 | case let (.insert(le, li), .insert(re, ri)): 22 | return le == re && li == ri 23 | 24 | case let (.move(le, lfi, lti), .move(re, rfi, rti)): 25 | return le == re && lfi == rfi && lti == rti 26 | 27 | default: 28 | return false 29 | } 30 | } 31 | } 32 | 33 | struct Heckel { 34 | static func diff(from fromArray: Array, to toArray: Array) -> [Difference] { 35 | var symbolTable: [Int: SymbolTableEntry] = [:] 36 | var oldElementReferences: [ElementReference] = [] 37 | var newElementReferences: [ElementReference] = [] 38 | 39 | stepFirst(newArray: toArray, symbolTable: &symbolTable, newElementReferences: &newElementReferences) 40 | stepSecond(oldArray: fromArray, symbolTable: &symbolTable, oldElementReferences: &oldElementReferences) 41 | stepThird(newElementReferences: &newElementReferences, oldElementReferences: &oldElementReferences) 42 | stepFourth(newElementReferences: &newElementReferences, oldElementReferences: &oldElementReferences) 43 | stepFifth(newElementReferences: &newElementReferences, oldElementReferences: &oldElementReferences) 44 | return stepSixth(newArray: toArray, oldArray: fromArray, newElementReferences: newElementReferences, oldElementReferences: oldElementReferences) 45 | } 46 | } 47 | 48 | private extension Heckel { 49 | static func stepFirst(newArray: Array, symbolTable: inout [Int: SymbolTableEntry], newElementReferences: inout [ElementReference]) { 50 | newArray.forEach { element in 51 | let entry = symbolTable[element.hashValue] ?? SymbolTableEntry() 52 | entry.newCounter.increment(withIndex: 0) 53 | newElementReferences.append(.symbolTable(entry: entry)) 54 | symbolTable[element.hashValue] = entry 55 | } 56 | } 57 | 58 | static func stepSecond(oldArray: Array, symbolTable: inout [Int: SymbolTableEntry], oldElementReferences: inout [ElementReference]) { 59 | oldArray.enumerated().forEach { index, element in 60 | let entry = symbolTable[element.hashValue] ?? SymbolTableEntry() 61 | entry.oldCounter.increment(withIndex: index) 62 | oldElementReferences.append(.symbolTable(entry: entry)) 63 | symbolTable[element.hashValue] = entry 64 | } 65 | } 66 | 67 | static func stepThird(newElementReferences: inout [ElementReference], oldElementReferences: inout [ElementReference]) { 68 | newElementReferences.enumerated().forEach { newIndex, reference in 69 | guard case let .symbolTable(entry: entry) = reference, 70 | case .one(let oldIndex) = entry.oldCounter, 71 | case .one = entry.newCounter else { return } 72 | 73 | newElementReferences[newIndex] = .theOther(at: oldIndex) 74 | oldElementReferences[oldIndex] = .theOther(at: newIndex) 75 | } 76 | } 77 | 78 | static func stepFourth(newElementReferences: inout [ElementReference], oldElementReferences: inout [ElementReference]) { 79 | let oldCount = oldElementReferences.count 80 | let newCount = newElementReferences.count 81 | if oldCount > 0, newCount > 0, 82 | case let .symbolTable(entry: newEntry) = newElementReferences[0], 83 | case let .symbolTable(entry: oldEntry) = oldElementReferences[0], 84 | newEntry === oldEntry { 85 | 86 | newElementReferences[0] = .theOther(at: 0) 87 | oldElementReferences[0] = .theOther(at: 0) 88 | } 89 | 90 | newElementReferences.enumerated().forEach { newIndex, _ in 91 | guard case let .theOther(at: oldIndex) = newElementReferences[newIndex], oldIndex < oldElementReferences.count - 1, newIndex < newElementReferences.count - 1, 92 | case let .symbolTable(entry: newEntry) = newElementReferences[newIndex + 1], 93 | case let .symbolTable(entry: oldEntry) = oldElementReferences[oldIndex + 1], 94 | newEntry === oldEntry else { return } 95 | 96 | newElementReferences[newIndex + 1] = .theOther(at: oldIndex + 1) 97 | oldElementReferences[oldIndex + 1] = .theOther(at: newIndex + 1) 98 | } 99 | } 100 | 101 | static func stepFifth(newElementReferences: inout [ElementReference], oldElementReferences: inout [ElementReference]) { 102 | let oldCount = oldElementReferences.count 103 | let newCount = newElementReferences.count 104 | if oldCount > 0, newCount > 0, 105 | case let .symbolTable(entry: newEntry) = newElementReferences[newCount - 1], 106 | case let .symbolTable(entry: oldEntry) = oldElementReferences[oldCount - 1], 107 | newEntry === oldEntry { 108 | 109 | newElementReferences[newCount - 1] = .theOther(at: oldCount - 1) 110 | oldElementReferences[oldCount - 1] = .theOther(at: newCount - 1) 111 | } 112 | 113 | newElementReferences.enumerated().reversed().forEach { newIndex, _ in 114 | guard case let .theOther(at: oldIndex) = newElementReferences[newIndex], oldIndex > 0, newIndex > 0, 115 | case let .symbolTable(entry: newEntry) = newElementReferences[newIndex - 1], 116 | case let .symbolTable(entry: oldEntry) = oldElementReferences[oldIndex - 1], 117 | newEntry === oldEntry else { return } 118 | 119 | newElementReferences[newIndex - 1] = .theOther(at: oldIndex - 1) 120 | oldElementReferences[oldIndex - 1] = .theOther(at: newIndex - 1) 121 | } 122 | } 123 | 124 | static func stepSixth(newArray: Array, oldArray: Array, newElementReferences: [ElementReference], oldElementReferences: [ElementReference]) -> [Difference] { 125 | var differences: [Difference] = [] 126 | var oldIndexOffsets: [Int: Int] = [:] 127 | 128 | var offsetByDelete = 0 129 | oldElementReferences.enumerated().forEach { oldIndex, reference in 130 | oldIndexOffsets[oldIndex] = offsetByDelete 131 | 132 | guard case .symbolTable = reference else { return } 133 | differences.append(.delete(element: oldArray[oldIndex], index: oldIndex)) 134 | offsetByDelete += 1 135 | } 136 | 137 | var offsetByInsert = 0 138 | newElementReferences.enumerated().forEach { newIndex, reference in 139 | switch reference { 140 | case .symbolTable: 141 | differences.append(.insert(element: newArray[newIndex], index: newIndex)) 142 | offsetByInsert += 1 143 | 144 | case .theOther(let oldIndex) where oldIndex - oldIndexOffsets[oldIndex]! != newIndex - offsetByInsert: 145 | differences.append(.move(element: newArray[newIndex], fromIndex: oldIndex, toIndex: newIndex)) 146 | 147 | default: 148 | break 149 | } 150 | } 151 | 152 | return differences 153 | } 154 | } 155 | 156 | private extension Heckel { 157 | enum Counter { 158 | case zero 159 | case one(index: Int) 160 | case many 161 | 162 | mutating func increment(withIndex index: Int) { 163 | switch self { 164 | case .zero: 165 | self = .one(index: index) 166 | 167 | default: 168 | self = .many 169 | } 170 | } 171 | } 172 | 173 | class SymbolTableEntry { 174 | var oldCounter: Counter = .zero 175 | var newCounter: Counter = .zero 176 | } 177 | 178 | enum ElementReference { 179 | case symbolTable(entry: SymbolTableEntry) 180 | case theOther(at: Int) 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /DifferenceAlgorithmComparison/Algorithm/Myers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Myers.swift 3 | // DifferenceAlgorithmComparison 4 | // 5 | // Created by Yuya Horita on 2018/02/09. 6 | // Copyright © 2018年 hy. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Myers { 12 | enum Script: CustomStringConvertible, Equatable { 13 | case delete(at: Int) 14 | case insert(from: Int, to: Int) 15 | case insertToHead(from: Int) 16 | case same 17 | 18 | var description: String { 19 | switch self { 20 | case .delete(let atIndex): 21 | return "D(\(atIndex))" 22 | 23 | case .insert(let fromIndex, let toIndex): 24 | return "I(\(fromIndex), \(toIndex))" 25 | 26 | case .insertToHead(let fromIndex): 27 | return "IH(\(fromIndex))" 28 | 29 | case .same: 30 | return "S" 31 | } 32 | } 33 | 34 | static func ==(lhs: Script, rhs: Script) -> Bool { 35 | switch (lhs, rhs) { 36 | case let (.delete(lfi), .delete(rfi)): 37 | return lfi == rfi 38 | 39 | case let (.insert(lfi, lti), .insert(rfi, rti)): 40 | return lfi == rfi && lti == rti 41 | 42 | case let (.insertToHead(lfi), .insertToHead(rfi)): 43 | return lfi == rfi 44 | 45 | case (.same, .same): 46 | return true 47 | 48 | default: 49 | return false 50 | } 51 | } 52 | } 53 | 54 | static func diff(from fromArray: Array, to toArray: Array) -> Array