├── .gitignore ├── Package.swift ├── README.md ├── Resources ├── Sdift │ ├── Info-iOS.plist │ └── Sdift.h └── SdiftTests │ └── Info-iOS.plist ├── Sdift.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── Sdift-iOS.xcscheme ├── Sources └── Sdift │ ├── Algorithm.swift │ ├── BackwardDirection.swift │ ├── Difference.swift │ ├── ForwardDirection.swift │ ├── ProgressTable.swift │ └── Slice.swift └── Tests ├── LinuxMain.swift └── SdiftTests ├── SdiftTests.swift └── XCTestManifests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata 5 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Sdift", 7 | products: [ 8 | .library(name: "Sdift", targets: ["Sdift"]), 9 | ], 10 | dependencies: [ 11 | ], 12 | targets: [ 13 | .target(name: "Sdift", dependencies: []), 14 | .testTarget(name: "SdiftTests", dependencies: ["Sdift"]), 15 | ] 16 | ) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sdift 2 | 3 | Swift myers diff library. 4 | 5 | Algorithm is based on this webpage. 6 | 7 | http://blog.robertelder.org/diff-algorithm/ 8 | 9 | ### example 10 | 11 | https://github.com/omochi/SdiftExample 12 | -------------------------------------------------------------------------------- /Resources/Sdift/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Resources/Sdift/Sdift.h: -------------------------------------------------------------------------------- 1 | // 2 | // Sdift.h 3 | // Sdift 4 | // 5 | // Created by omochimetaru on 2018/06/29. 6 | // Copyright © 2018年 omochimetaru.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Sdift. 12 | FOUNDATION_EXPORT double SdiftVersionNumber; 13 | 14 | //! Project version string for Sdift. 15 | FOUNDATION_EXPORT const unsigned char SdiftVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Resources/SdiftTests/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Sdift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D62FC84B20E5E1E2003EF7A6 /* Sdift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D62FC84120E5E1E2003EF7A6 /* Sdift.framework */; }; 11 | D62FC88220E5E2D8003EF7A6 /* Sdift.h in Headers */ = {isa = PBXBuildFile; fileRef = D62FC87320E5E2D7003EF7A6 /* Sdift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | D62FC88420E5E2D8003EF7A6 /* BackwardDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FC87720E5E2D7003EF7A6 /* BackwardDirection.swift */; }; 13 | D62FC88520E5E2D8003EF7A6 /* Algorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FC87820E5E2D7003EF7A6 /* Algorithm.swift */; }; 14 | D62FC88620E5E2D8003EF7A6 /* Slice.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FC87920E5E2D7003EF7A6 /* Slice.swift */; }; 15 | D62FC88720E5E2D8003EF7A6 /* Difference.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FC87A20E5E2D7003EF7A6 /* Difference.swift */; }; 16 | D62FC88820E5E2D8003EF7A6 /* ProgressTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FC87B20E5E2D7003EF7A6 /* ProgressTable.swift */; }; 17 | D62FC88920E5E2D8003EF7A6 /* ForwardDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FC87C20E5E2D7003EF7A6 /* ForwardDirection.swift */; }; 18 | D62FC88B20E5E2DF003EF7A6 /* SdiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FC86C20E5E2D7003EF7A6 /* SdiftTests.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | D62FC84C20E5E1E2003EF7A6 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = D62FC83820E5E1E2003EF7A6 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = D62FC84020E5E1E2003EF7A6; 27 | remoteInfo = Sdift; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | D62FC84120E5E1E2003EF7A6 /* Sdift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Sdift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | D62FC84A20E5E1E2003EF7A6 /* SdiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SdiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | D62FC86B20E5E2D7003EF7A6 /* XCTestManifests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTestManifests.swift; sourceTree = ""; }; 35 | D62FC86C20E5E2D7003EF7A6 /* SdiftTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SdiftTests.swift; sourceTree = ""; }; 36 | D62FC86D20E5E2D7003EF7A6 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; 37 | D62FC87120E5E2D7003EF7A6 /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 38 | D62FC87320E5E2D7003EF7A6 /* Sdift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sdift.h; sourceTree = ""; }; 39 | D62FC87420E5E2D7003EF7A6 /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 40 | D62FC87720E5E2D7003EF7A6 /* BackwardDirection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackwardDirection.swift; sourceTree = ""; }; 41 | D62FC87820E5E2D7003EF7A6 /* Algorithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Algorithm.swift; sourceTree = ""; }; 42 | D62FC87920E5E2D7003EF7A6 /* Slice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Slice.swift; sourceTree = ""; }; 43 | D62FC87A20E5E2D7003EF7A6 /* Difference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Difference.swift; sourceTree = ""; }; 44 | D62FC87B20E5E2D7003EF7A6 /* ProgressTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressTable.swift; sourceTree = ""; }; 45 | D62FC87C20E5E2D7003EF7A6 /* ForwardDirection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForwardDirection.swift; sourceTree = ""; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | D62FC83E20E5E1E2003EF7A6 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | D62FC84720E5E1E2003EF7A6 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | D62FC84B20E5E1E2003EF7A6 /* Sdift.framework in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXFrameworksBuildPhase section */ 65 | 66 | /* Begin PBXGroup section */ 67 | D62FC83720E5E1E2003EF7A6 = { 68 | isa = PBXGroup; 69 | children = ( 70 | D62FC86E20E5E2D7003EF7A6 /* Resources */, 71 | D62FC87520E5E2D7003EF7A6 /* Sources */, 72 | D62FC86920E5E2D7003EF7A6 /* Tests */, 73 | D62FC84220E5E1E2003EF7A6 /* Products */, 74 | ); 75 | sourceTree = ""; 76 | }; 77 | D62FC84220E5E1E2003EF7A6 /* Products */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | D62FC84120E5E1E2003EF7A6 /* Sdift.framework */, 81 | D62FC84A20E5E1E2003EF7A6 /* SdiftTests.xctest */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | D62FC86920E5E2D7003EF7A6 /* Tests */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | D62FC86A20E5E2D7003EF7A6 /* SdiftTests */, 90 | D62FC86D20E5E2D7003EF7A6 /* LinuxMain.swift */, 91 | ); 92 | path = Tests; 93 | sourceTree = ""; 94 | }; 95 | D62FC86A20E5E2D7003EF7A6 /* SdiftTests */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | D62FC86B20E5E2D7003EF7A6 /* XCTestManifests.swift */, 99 | D62FC86C20E5E2D7003EF7A6 /* SdiftTests.swift */, 100 | ); 101 | path = SdiftTests; 102 | sourceTree = ""; 103 | }; 104 | D62FC86E20E5E2D7003EF7A6 /* Resources */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | D62FC87220E5E2D7003EF7A6 /* Sdift */, 108 | D62FC86F20E5E2D7003EF7A6 /* SdiftTests */, 109 | ); 110 | path = Resources; 111 | sourceTree = ""; 112 | }; 113 | D62FC86F20E5E2D7003EF7A6 /* SdiftTests */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | D62FC87120E5E2D7003EF7A6 /* Info-iOS.plist */, 117 | ); 118 | path = SdiftTests; 119 | sourceTree = ""; 120 | }; 121 | D62FC87220E5E2D7003EF7A6 /* Sdift */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | D62FC87320E5E2D7003EF7A6 /* Sdift.h */, 125 | D62FC87420E5E2D7003EF7A6 /* Info-iOS.plist */, 126 | ); 127 | path = Sdift; 128 | sourceTree = ""; 129 | }; 130 | D62FC87520E5E2D7003EF7A6 /* Sources */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | D62FC87620E5E2D7003EF7A6 /* Sdift */, 134 | ); 135 | path = Sources; 136 | sourceTree = ""; 137 | }; 138 | D62FC87620E5E2D7003EF7A6 /* Sdift */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | D62FC87720E5E2D7003EF7A6 /* BackwardDirection.swift */, 142 | D62FC87820E5E2D7003EF7A6 /* Algorithm.swift */, 143 | D62FC87920E5E2D7003EF7A6 /* Slice.swift */, 144 | D62FC87A20E5E2D7003EF7A6 /* Difference.swift */, 145 | D62FC87B20E5E2D7003EF7A6 /* ProgressTable.swift */, 146 | D62FC87C20E5E2D7003EF7A6 /* ForwardDirection.swift */, 147 | ); 148 | path = Sdift; 149 | sourceTree = ""; 150 | }; 151 | /* End PBXGroup section */ 152 | 153 | /* Begin PBXHeadersBuildPhase section */ 154 | D62FC83C20E5E1E2003EF7A6 /* Headers */ = { 155 | isa = PBXHeadersBuildPhase; 156 | buildActionMask = 2147483647; 157 | files = ( 158 | D62FC88220E5E2D8003EF7A6 /* Sdift.h in Headers */, 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXHeadersBuildPhase section */ 163 | 164 | /* Begin PBXNativeTarget section */ 165 | D62FC84020E5E1E2003EF7A6 /* Sdift-iOS */ = { 166 | isa = PBXNativeTarget; 167 | buildConfigurationList = D62FC85520E5E1E2003EF7A6 /* Build configuration list for PBXNativeTarget "Sdift-iOS" */; 168 | buildPhases = ( 169 | D62FC83C20E5E1E2003EF7A6 /* Headers */, 170 | D62FC83D20E5E1E2003EF7A6 /* Sources */, 171 | D62FC83E20E5E1E2003EF7A6 /* Frameworks */, 172 | D62FC83F20E5E1E2003EF7A6 /* Resources */, 173 | ); 174 | buildRules = ( 175 | ); 176 | dependencies = ( 177 | ); 178 | name = "Sdift-iOS"; 179 | productName = Sdift; 180 | productReference = D62FC84120E5E1E2003EF7A6 /* Sdift.framework */; 181 | productType = "com.apple.product-type.framework"; 182 | }; 183 | D62FC84920E5E1E2003EF7A6 /* SdiftTests-iOS */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = D62FC85820E5E1E2003EF7A6 /* Build configuration list for PBXNativeTarget "SdiftTests-iOS" */; 186 | buildPhases = ( 187 | D62FC84620E5E1E2003EF7A6 /* Sources */, 188 | D62FC84720E5E1E2003EF7A6 /* Frameworks */, 189 | D62FC84820E5E1E2003EF7A6 /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | D62FC84D20E5E1E2003EF7A6 /* PBXTargetDependency */, 195 | ); 196 | name = "SdiftTests-iOS"; 197 | productName = SdiftTests; 198 | productReference = D62FC84A20E5E1E2003EF7A6 /* SdiftTests.xctest */; 199 | productType = "com.apple.product-type.bundle.unit-test"; 200 | }; 201 | /* End PBXNativeTarget section */ 202 | 203 | /* Begin PBXProject section */ 204 | D62FC83820E5E1E2003EF7A6 /* Project object */ = { 205 | isa = PBXProject; 206 | attributes = { 207 | LastSwiftUpdateCheck = 1000; 208 | LastUpgradeCheck = 1000; 209 | ORGANIZATIONNAME = omochimetaru.com; 210 | TargetAttributes = { 211 | D62FC84020E5E1E2003EF7A6 = { 212 | CreatedOnToolsVersion = 10.0; 213 | }; 214 | D62FC84920E5E1E2003EF7A6 = { 215 | CreatedOnToolsVersion = 10.0; 216 | }; 217 | }; 218 | }; 219 | buildConfigurationList = D62FC83B20E5E1E2003EF7A6 /* Build configuration list for PBXProject "Sdift" */; 220 | compatibilityVersion = "Xcode 9.3"; 221 | developmentRegion = en; 222 | hasScannedForEncodings = 0; 223 | knownRegions = ( 224 | en, 225 | ); 226 | mainGroup = D62FC83720E5E1E2003EF7A6; 227 | productRefGroup = D62FC84220E5E1E2003EF7A6 /* Products */; 228 | projectDirPath = ""; 229 | projectRoot = ""; 230 | targets = ( 231 | D62FC84020E5E1E2003EF7A6 /* Sdift-iOS */, 232 | D62FC84920E5E1E2003EF7A6 /* SdiftTests-iOS */, 233 | ); 234 | }; 235 | /* End PBXProject section */ 236 | 237 | /* Begin PBXResourcesBuildPhase section */ 238 | D62FC83F20E5E1E2003EF7A6 /* Resources */ = { 239 | isa = PBXResourcesBuildPhase; 240 | buildActionMask = 2147483647; 241 | files = ( 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | }; 245 | D62FC84820E5E1E2003EF7A6 /* Resources */ = { 246 | isa = PBXResourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXResourcesBuildPhase section */ 253 | 254 | /* Begin PBXSourcesBuildPhase section */ 255 | D62FC83D20E5E1E2003EF7A6 /* Sources */ = { 256 | isa = PBXSourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | D62FC88520E5E2D8003EF7A6 /* Algorithm.swift in Sources */, 260 | D62FC88920E5E2D8003EF7A6 /* ForwardDirection.swift in Sources */, 261 | D62FC88620E5E2D8003EF7A6 /* Slice.swift in Sources */, 262 | D62FC88420E5E2D8003EF7A6 /* BackwardDirection.swift in Sources */, 263 | D62FC88820E5E2D8003EF7A6 /* ProgressTable.swift in Sources */, 264 | D62FC88720E5E2D8003EF7A6 /* Difference.swift in Sources */, 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | D62FC84620E5E1E2003EF7A6 /* Sources */ = { 269 | isa = PBXSourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | D62FC88B20E5E2DF003EF7A6 /* SdiftTests.swift in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXSourcesBuildPhase section */ 277 | 278 | /* Begin PBXTargetDependency section */ 279 | D62FC84D20E5E1E2003EF7A6 /* PBXTargetDependency */ = { 280 | isa = PBXTargetDependency; 281 | target = D62FC84020E5E1E2003EF7A6 /* Sdift-iOS */; 282 | targetProxy = D62FC84C20E5E1E2003EF7A6 /* PBXContainerItemProxy */; 283 | }; 284 | /* End PBXTargetDependency section */ 285 | 286 | /* Begin XCBuildConfiguration section */ 287 | D62FC85320E5E1E2003EF7A6 /* Debug */ = { 288 | isa = XCBuildConfiguration; 289 | buildSettings = { 290 | ALWAYS_SEARCH_USER_PATHS = NO; 291 | CLANG_ANALYZER_NONNULL = YES; 292 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 293 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 294 | CLANG_CXX_LIBRARY = "libc++"; 295 | CLANG_ENABLE_MODULES = YES; 296 | CLANG_ENABLE_OBJC_ARC = YES; 297 | CLANG_ENABLE_OBJC_WEAK = YES; 298 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 299 | CLANG_WARN_BOOL_CONVERSION = YES; 300 | CLANG_WARN_COMMA = YES; 301 | CLANG_WARN_CONSTANT_CONVERSION = YES; 302 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 303 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 304 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 305 | CLANG_WARN_EMPTY_BODY = YES; 306 | CLANG_WARN_ENUM_CONVERSION = YES; 307 | CLANG_WARN_INFINITE_RECURSION = YES; 308 | CLANG_WARN_INT_CONVERSION = YES; 309 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 310 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 311 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 312 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 313 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 314 | CLANG_WARN_STRICT_PROTOTYPES = YES; 315 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 316 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | CODE_SIGN_IDENTITY = "iPhone Developer"; 320 | COPY_PHASE_STRIP = NO; 321 | CURRENT_PROJECT_VERSION = 1; 322 | DEBUG_INFORMATION_FORMAT = dwarf; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | ENABLE_TESTABILITY = YES; 325 | GCC_C_LANGUAGE_STANDARD = gnu11; 326 | GCC_DYNAMIC_NO_PIC = NO; 327 | GCC_NO_COMMON_BLOCKS = YES; 328 | GCC_OPTIMIZATION_LEVEL = 0; 329 | GCC_PREPROCESSOR_DEFINITIONS = ( 330 | "DEBUG=1", 331 | "$(inherited)", 332 | ); 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 340 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 341 | ONLY_ACTIVE_ARCH = YES; 342 | SDKROOT = iphoneos; 343 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 344 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 345 | VERSIONING_SYSTEM = "apple-generic"; 346 | VERSION_INFO_PREFIX = ""; 347 | }; 348 | name = Debug; 349 | }; 350 | D62FC85420E5E1E2003EF7A6 /* Release */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ALWAYS_SEARCH_USER_PATHS = NO; 354 | CLANG_ANALYZER_NONNULL = YES; 355 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 356 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 357 | CLANG_CXX_LIBRARY = "libc++"; 358 | CLANG_ENABLE_MODULES = YES; 359 | CLANG_ENABLE_OBJC_ARC = YES; 360 | CLANG_ENABLE_OBJC_WEAK = YES; 361 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 362 | CLANG_WARN_BOOL_CONVERSION = YES; 363 | CLANG_WARN_COMMA = YES; 364 | CLANG_WARN_CONSTANT_CONVERSION = YES; 365 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 366 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 367 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 368 | CLANG_WARN_EMPTY_BODY = YES; 369 | CLANG_WARN_ENUM_CONVERSION = YES; 370 | CLANG_WARN_INFINITE_RECURSION = YES; 371 | CLANG_WARN_INT_CONVERSION = YES; 372 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 373 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 374 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 375 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 376 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 377 | CLANG_WARN_STRICT_PROTOTYPES = YES; 378 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 379 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 380 | CLANG_WARN_UNREACHABLE_CODE = YES; 381 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 382 | CODE_SIGN_IDENTITY = "iPhone Developer"; 383 | COPY_PHASE_STRIP = NO; 384 | CURRENT_PROJECT_VERSION = 1; 385 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 386 | ENABLE_NS_ASSERTIONS = NO; 387 | ENABLE_STRICT_OBJC_MSGSEND = YES; 388 | GCC_C_LANGUAGE_STANDARD = gnu11; 389 | GCC_NO_COMMON_BLOCKS = YES; 390 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 391 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 392 | GCC_WARN_UNDECLARED_SELECTOR = YES; 393 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 394 | GCC_WARN_UNUSED_FUNCTION = YES; 395 | GCC_WARN_UNUSED_VARIABLE = YES; 396 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 397 | MTL_ENABLE_DEBUG_INFO = NO; 398 | SDKROOT = iphoneos; 399 | SWIFT_COMPILATION_MODE = wholemodule; 400 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 401 | VALIDATE_PRODUCT = YES; 402 | VERSIONING_SYSTEM = "apple-generic"; 403 | VERSION_INFO_PREFIX = ""; 404 | }; 405 | name = Release; 406 | }; 407 | D62FC85620E5E1E2003EF7A6 /* Debug */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | CODE_SIGN_IDENTITY = ""; 411 | CODE_SIGN_STYLE = Automatic; 412 | DEFINES_MODULE = YES; 413 | DYLIB_COMPATIBILITY_VERSION = 1; 414 | DYLIB_CURRENT_VERSION = 1; 415 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 416 | INFOPLIST_FILE = "$(SRCROOT)/Resources/Sdift/Info-iOS.plist"; 417 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 418 | LD_RUNPATH_SEARCH_PATHS = ( 419 | "$(inherited)", 420 | "@executable_path/Frameworks", 421 | "@loader_path/Frameworks", 422 | ); 423 | PRODUCT_BUNDLE_IDENTIFIER = com.omochimetaru.Sdift; 424 | PRODUCT_NAME = Sdift; 425 | SKIP_INSTALL = YES; 426 | SWIFT_VERSION = 4.2; 427 | TARGETED_DEVICE_FAMILY = "1,2"; 428 | }; 429 | name = Debug; 430 | }; 431 | D62FC85720E5E1E2003EF7A6 /* Release */ = { 432 | isa = XCBuildConfiguration; 433 | buildSettings = { 434 | CODE_SIGN_IDENTITY = ""; 435 | CODE_SIGN_STYLE = Automatic; 436 | DEFINES_MODULE = YES; 437 | DYLIB_COMPATIBILITY_VERSION = 1; 438 | DYLIB_CURRENT_VERSION = 1; 439 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 440 | INFOPLIST_FILE = "$(SRCROOT)/Resources/Sdift/Info-iOS.plist"; 441 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 442 | LD_RUNPATH_SEARCH_PATHS = ( 443 | "$(inherited)", 444 | "@executable_path/Frameworks", 445 | "@loader_path/Frameworks", 446 | ); 447 | PRODUCT_BUNDLE_IDENTIFIER = com.omochimetaru.Sdift; 448 | PRODUCT_NAME = Sdift; 449 | SKIP_INSTALL = YES; 450 | SWIFT_VERSION = 4.2; 451 | TARGETED_DEVICE_FAMILY = "1,2"; 452 | }; 453 | name = Release; 454 | }; 455 | D62FC85920E5E1E2003EF7A6 /* Debug */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 459 | CODE_SIGN_STYLE = Automatic; 460 | INFOPLIST_FILE = "Resources/SdiftTests/Info-iOS.plist"; 461 | LD_RUNPATH_SEARCH_PATHS = ( 462 | "$(inherited)", 463 | "@executable_path/Frameworks", 464 | "@loader_path/Frameworks", 465 | ); 466 | PRODUCT_BUNDLE_IDENTIFIER = com.omochimetaru.SdiftTests; 467 | PRODUCT_NAME = SdiftTests; 468 | SWIFT_VERSION = 4.2; 469 | TARGETED_DEVICE_FAMILY = "1,2"; 470 | }; 471 | name = Debug; 472 | }; 473 | D62FC85A20E5E1E2003EF7A6 /* Release */ = { 474 | isa = XCBuildConfiguration; 475 | buildSettings = { 476 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 477 | CODE_SIGN_STYLE = Automatic; 478 | INFOPLIST_FILE = "Resources/SdiftTests/Info-iOS.plist"; 479 | LD_RUNPATH_SEARCH_PATHS = ( 480 | "$(inherited)", 481 | "@executable_path/Frameworks", 482 | "@loader_path/Frameworks", 483 | ); 484 | PRODUCT_BUNDLE_IDENTIFIER = com.omochimetaru.SdiftTests; 485 | PRODUCT_NAME = SdiftTests; 486 | SWIFT_VERSION = 4.2; 487 | TARGETED_DEVICE_FAMILY = "1,2"; 488 | }; 489 | name = Release; 490 | }; 491 | /* End XCBuildConfiguration section */ 492 | 493 | /* Begin XCConfigurationList section */ 494 | D62FC83B20E5E1E2003EF7A6 /* Build configuration list for PBXProject "Sdift" */ = { 495 | isa = XCConfigurationList; 496 | buildConfigurations = ( 497 | D62FC85320E5E1E2003EF7A6 /* Debug */, 498 | D62FC85420E5E1E2003EF7A6 /* Release */, 499 | ); 500 | defaultConfigurationIsVisible = 0; 501 | defaultConfigurationName = Release; 502 | }; 503 | D62FC85520E5E1E2003EF7A6 /* Build configuration list for PBXNativeTarget "Sdift-iOS" */ = { 504 | isa = XCConfigurationList; 505 | buildConfigurations = ( 506 | D62FC85620E5E1E2003EF7A6 /* Debug */, 507 | D62FC85720E5E1E2003EF7A6 /* Release */, 508 | ); 509 | defaultConfigurationIsVisible = 0; 510 | defaultConfigurationName = Release; 511 | }; 512 | D62FC85820E5E1E2003EF7A6 /* Build configuration list for PBXNativeTarget "SdiftTests-iOS" */ = { 513 | isa = XCConfigurationList; 514 | buildConfigurations = ( 515 | D62FC85920E5E1E2003EF7A6 /* Debug */, 516 | D62FC85A20E5E1E2003EF7A6 /* Release */, 517 | ); 518 | defaultConfigurationIsVisible = 0; 519 | defaultConfigurationName = Release; 520 | }; 521 | /* End XCConfigurationList section */ 522 | }; 523 | rootObject = D62FC83820E5E1E2003EF7A6 /* Project object */; 524 | } 525 | -------------------------------------------------------------------------------- /Sdift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sdift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sdift.xcodeproj/xcshareddata/xcschemes/Sdift-iOS.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 | -------------------------------------------------------------------------------- /Sources/Sdift/Algorithm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func difference 4 | (old: C, new: C) -> Difference 5 | where C.Element : Equatable 6 | { 7 | return difference(old: old, 8 | new: new, 9 | equals: { $0 == $1 }) 10 | } 11 | 12 | private struct CacheKey : Hashable { 13 | var oldIndex: Int 14 | var newIndex: Int 15 | } 16 | 17 | public func difference( 18 | old: OC, 19 | new: NC, 20 | equals: @escaping (OC.Element, NC.Element) -> Bool) -> Difference 21 | { 22 | return difference(old: Array(old), 23 | new: Array(new), 24 | equals: equals) 25 | } 26 | 27 | public func difference( 28 | old: [O], 29 | new: [N], 30 | equals: @escaping (O, N) -> Bool) -> Difference 31 | { 32 | var solver = Solver(old: old, new: new, equals: equals) 33 | return solver.difference() 34 | } 35 | 36 | internal struct Solver { 37 | private let old: [O] 38 | private let new: [N] 39 | private let equalsImpl: (O, N) -> Bool 40 | 41 | public init(old: [O], 42 | new: [N], 43 | equals equalsImpl: @escaping (O, N) -> Bool) 44 | { 45 | self.old = old 46 | self.new = new 47 | self.equalsImpl = equalsImpl 48 | } 49 | 50 | private var equalCache: [CacheKey: Bool] = [:] 51 | 52 | private mutating func rawEquals(oldIndex: Int, newIndex: Int) -> Bool { 53 | let cacheKey = CacheKey(oldIndex: oldIndex, newIndex: newIndex) 54 | if let cache = equalCache[cacheKey] { 55 | return cache 56 | } 57 | 58 | let oldElement = old[oldIndex] 59 | let newElement = new[newIndex] 60 | let result = equalsImpl(oldElement, newElement) 61 | equalCache[cacheKey] = result 62 | return result 63 | } 64 | 65 | public mutating func difference() -> Difference { 66 | let oldSlice = Slice(elements: old, 67 | offset: 0, 68 | count: old.count) 69 | let newSlice = Slice(elements: new, 70 | offset: 0, 71 | count: new.count) 72 | let diffItems = self.difference(old: oldSlice, new: newSlice) 73 | return Difference(diffItems) 74 | } 75 | 76 | private mutating func difference(old: Slice, new: Slice) -> [Difference.Item] { 77 | func equals(oldIndex: Int, newIndex: Int) -> Bool { 78 | return rawEquals(oldIndex: old.offset + oldIndex, 79 | newIndex: new.offset + newIndex) 80 | } 81 | 82 | if new.count == 0 { 83 | return (0.. Int { 100 | return lengthDiff - k 101 | } 102 | 103 | let forwardTable = ProgressTable(size: tableSize) 104 | let backwardTable = ProgressTable(size: tableSize) 105 | 106 | let stepNum: Int = (maxDistance + 1) / 2 + 1 107 | 108 | for step in 0..= old.count 165 | if isCrossing { 166 | if snakeStartX == snakeEndX { 167 | if step == 0 { 168 | // maxDistanceのガードがあるからここには来ない 169 | assertionFailure() 170 | } else if step == 1 { 171 | assert(snakeEndX == old.count) 172 | assert(snakeEndY == new.count) 173 | assert(abs(lengthDiff) == 1) 174 | if new.count < old.count { 175 | return difference(old: old[new.count..= old.count 234 | if isCrossing { 235 | if snakeStartX == snakeEndX { 236 | if step == 0 { 237 | return [] 238 | } 239 | } 240 | 241 | return difference(old: old[0..<(old.count - snakeEndX)], 242 | new: new[0..<(new.count - snakeEndY)]) + 243 | difference(old: old[(old.count - snakeStartX)..(new: NC, 24 | insert: (Int, NC.Element) -> Void, 25 | update: (Int, NC.Element) -> Void, 26 | remove: (Int) -> Void) 27 | { 28 | apply(new: Array(new), 29 | insert: insert, 30 | update: update, 31 | remove: remove) 32 | } 33 | 34 | public func apply(new: [N], 35 | insert: (Int, N) -> Void, 36 | update: (Int, N) -> Void, 37 | remove: (Int) -> Void) 38 | { 39 | var oldIndex = 0 40 | var oldIndexOffset = 0 41 | var newIndex = 0 42 | for item in items { 43 | while oldIndex < item.oldIndex { 44 | update(oldIndex + oldIndexOffset, new[newIndex]) 45 | oldIndex += 1 46 | newIndex += 1 47 | } 48 | switch item { 49 | case .remove: 50 | remove(oldIndex + oldIndexOffset) 51 | oldIndex += 1 52 | oldIndexOffset -= 1 53 | case .insert(oldIndex: _, newIndex: _): 54 | insert(oldIndex + oldIndexOffset, new[newIndex]) 55 | oldIndexOffset += 1 56 | newIndex += 1 57 | } 58 | } 59 | while newIndex < new.count { 60 | update(oldIndex + oldIndexOffset, new[newIndex]) 61 | oldIndex += 1 62 | newIndex += 1 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/Sdift/ForwardDirection.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal enum ForwardDirection { 4 | case down 5 | case right 6 | } 7 | -------------------------------------------------------------------------------- /Sources/Sdift/ProgressTable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class ProgressTable { 4 | private var buffer: [Int] 5 | 6 | public init(size: Int) { 7 | self.buffer = Array(repeating: 0, count: size) 8 | } 9 | 10 | public var size: Int { 11 | return buffer.count 12 | } 13 | 14 | public subscript(k k: Int) -> Int { 15 | get { 16 | return buffer[wrap(k: k)] 17 | } 18 | set { 19 | buffer[wrap(k: k)] = newValue 20 | } 21 | } 22 | 23 | private func wrap(k: Int) -> Int { 24 | var k = k 25 | k %= size 26 | if k < 0 { 27 | k += size 28 | } 29 | return k 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Sdift/Slice.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class Slice { 4 | public let elements: [E] 5 | public let offset: Int 6 | public let count: Int 7 | 8 | public init(elements: [E], 9 | offset: Int, 10 | count: Int) 11 | { 12 | precondition(0 <= offset) 13 | precondition(0 <= count) 14 | precondition(offset + count <= elements.count) 15 | 16 | self.elements = elements 17 | self.offset = offset 18 | self.count = count 19 | } 20 | 21 | public subscript(range: Range) -> Slice { 22 | get { 23 | return Slice(elements: elements, 24 | offset: offset + range.lowerBound, 25 | count: range.count) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import SdiftTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += SdiftTests.allTests() 7 | XCTMain(tests) -------------------------------------------------------------------------------- /Tests/SdiftTests/SdiftTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Sdift 3 | 4 | extension Difference { 5 | public func reconstruct(old: [E], 6 | new: [E], 7 | append: (E) -> Void) 8 | { 9 | var oldIndex = 0 10 | for item in items { 11 | while oldIndex < item.oldIndex { 12 | append(old[oldIndex]) 13 | oldIndex += 1 14 | } 15 | switch item { 16 | case .remove: 17 | oldIndex += 1 18 | case .insert(oldIndex: _, newIndex: let newIndex): 19 | append(new[newIndex]) 20 | } 21 | } 22 | while oldIndex < old.count { 23 | append(old[oldIndex]) 24 | oldIndex += 1 25 | } 26 | } 27 | } 28 | 29 | final class SdiftTests: XCTestCase { 30 | func testDifference0() { 31 | let old = "" 32 | let new = "" 33 | let diff = difference(old: old, new: new) 34 | XCTAssertEqual(diff.items.count, 0) 35 | } 36 | 37 | func testDifference1() { 38 | let old = "a" 39 | let new = "" 40 | let diff = difference(old: old, new: new) 41 | XCTAssertEqual(diff.items.count, 1) 42 | XCTAssertEqual(diff.items[0], .remove(oldIndex: 0)) 43 | } 44 | 45 | func testDifference2() { 46 | let old = "abc" 47 | let new = "" 48 | let diff = difference(old: old, new: new) 49 | XCTAssertEqual(diff.items.count, 3) 50 | XCTAssertEqual(diff.items[0], .remove(oldIndex: 0)) 51 | XCTAssertEqual(diff.items[1], .remove(oldIndex: 1)) 52 | XCTAssertEqual(diff.items[2], .remove(oldIndex: 2)) 53 | } 54 | 55 | func testDifference3() { 56 | let old = "" 57 | let new = "a" 58 | let diff = difference(old: old, new: new) 59 | XCTAssertEqual(diff.items.count, 1) 60 | XCTAssertEqual(diff.items[0], .insert(oldIndex: 0, newIndex: 0)) 61 | } 62 | 63 | func testDifference4() { 64 | let old = "" 65 | let new = "abc" 66 | let diff = difference(old: old, new: new) 67 | XCTAssertEqual(diff.items.count, 3) 68 | XCTAssertEqual(diff.items[0], .insert(oldIndex: 0, newIndex: 0)) 69 | XCTAssertEqual(diff.items[1], .insert(oldIndex: 0, newIndex: 1)) 70 | XCTAssertEqual(diff.items[2], .insert(oldIndex: 0, newIndex: 2)) 71 | } 72 | 73 | func testDifference5() { 74 | let old = "abc" 75 | let new = "def" 76 | let diff = difference(old: old, new: new) 77 | XCTAssertEqual(diff.items.count, 6) 78 | XCTAssertEqual(diff.items[0], .remove(oldIndex: 0)) 79 | XCTAssertEqual(diff.items[1], .remove(oldIndex: 1)) 80 | XCTAssertEqual(diff.items[2], .remove(oldIndex: 2)) 81 | XCTAssertEqual(diff.items[3], .insert(oldIndex: 3, newIndex: 0)) 82 | XCTAssertEqual(diff.items[4], .insert(oldIndex: 3, newIndex: 1)) 83 | XCTAssertEqual(diff.items[5], .insert(oldIndex: 3, newIndex: 2)) 84 | } 85 | 86 | func testDifference6() { 87 | let old = "abcabba" 88 | let new = "cbabac" 89 | let diff = difference(old: old, new: new) 90 | XCTAssertEqual(diff.items.count, 5) 91 | XCTAssertEqual(diff.items[0], .remove(oldIndex: 0)) 92 | XCTAssertEqual(diff.items[1], .insert(oldIndex: 1, newIndex: 0)) 93 | XCTAssertEqual(diff.items[2], .remove(oldIndex: 2)) 94 | XCTAssertEqual(diff.items[3], .remove(oldIndex: 5)) 95 | XCTAssertEqual(diff.items[4], .insert(oldIndex: 7, newIndex: 5)) 96 | } 97 | 98 | func testDifference7() { 99 | let old = "abgdef" 100 | let new = "gh" 101 | let diff = difference(old: old, new: new) 102 | XCTAssertEqual(diff.items.count, 6) 103 | XCTAssertEqual(diff.items[0], .remove(oldIndex: 0)) 104 | XCTAssertEqual(diff.items[1], .remove(oldIndex: 1)) 105 | XCTAssertEqual(diff.items[2], .remove(oldIndex: 3)) 106 | XCTAssertEqual(diff.items[3], .remove(oldIndex: 4)) 107 | XCTAssertEqual(diff.items[4], .insert(oldIndex: 5, newIndex: 1)) 108 | XCTAssertEqual(diff.items[5], .remove(oldIndex: 5)) 109 | } 110 | 111 | func assertReconstruct(old: String, new: String) { 112 | let diff = difference(old: old, new: new) 113 | var renew: String = "" 114 | diff.reconstruct(old: Array(old), new: Array(new)) { renew.append($0) } 115 | XCTAssertEqual(new, renew) 116 | } 117 | 118 | func testReconstruct() { 119 | // 0x0 120 | assertReconstruct(old: "", new: "") 121 | // 1x0 122 | assertReconstruct(old: "a", new: "") 123 | // 0x1 124 | assertReconstruct(old: "", new: "a") 125 | // 1x1 126 | assertReconstruct(old: "a", new: "a") 127 | assertReconstruct(old: "a", new: "b") 128 | // 2x0 129 | assertReconstruct(old: "ab", new: "") 130 | // 2x1 131 | assertReconstruct(old: "ab", new: "c") 132 | assertReconstruct(old: "ab", new: "a") 133 | assertReconstruct(old: "ab", new: "b") 134 | assertReconstruct(old: "aa", new: "a") 135 | // 0x2 136 | assertReconstruct(old: "", new: "ab") 137 | // 1x2 138 | assertReconstruct(old: "a", new: "bc") 139 | assertReconstruct(old: "a", new: "ab") 140 | assertReconstruct(old: "a", new: "ba") 141 | assertReconstruct(old: "a", new: "aa") 142 | 143 | // 2x2 (0) 144 | assertReconstruct(old: "ab", new: "cd") 145 | // 2x2 (1) 146 | assertReconstruct(old: "ab", new: "ad") 147 | assertReconstruct(old: "ab", new: "ca") 148 | assertReconstruct(old: "ab", new: "bd") 149 | assertReconstruct(old: "ab", new: "cb") 150 | // 2x2 (2) 151 | assertReconstruct(old: "aa", new: "ad") 152 | assertReconstruct(old: "ab", new: "ab") 153 | assertReconstruct(old: "ab", new: "aa") 154 | 155 | assertReconstruct(old: "ab", new: "bb") 156 | assertReconstruct(old: "ab", new: "ba") 157 | 158 | assertReconstruct(old: "aa", new: "ba") 159 | // 2x2 (3) 160 | assertReconstruct(old: "aa", new: "ab") 161 | assertReconstruct(old: "aa", new: "ba") 162 | assertReconstruct(old: "ab", new: "aa") 163 | assertReconstruct(old: "ba", new: "aa") 164 | // 2x2 (4) 165 | assertReconstruct(old: "aa", new: "aa") 166 | 167 | // 168 | assertReconstruct(old: "abcabba", new: "cbabac") 169 | assertReconstruct(old: "abgdef", new: "gh") 170 | } 171 | 172 | func assertApply(old: String, new: String) { 173 | var old = Array(old) 174 | let new = Array(new) 175 | let diff = difference(old: old, new: new) 176 | diff.apply(new: new, 177 | insert: { (index, item) in 178 | old.insert(item, at: index) }, 179 | update: { (index, item) in 180 | XCTAssertEqual(old[index], item) }, 181 | remove: { (index) in 182 | old.remove(at: index) }) 183 | XCTAssertEqual(old, new) 184 | } 185 | 186 | func testApply() { 187 | assertApply(old: "a", new: "ab") 188 | assertApply(old: "a", new: "ba") 189 | assertApply(old: "abcabba", new: "cbabac") 190 | assertApply(old: "abgdef", new: "gh") 191 | } 192 | 193 | static var allTests = [ 194 | ("testDifference0", testDifference0), 195 | ("testDifference1", testDifference1), 196 | ("testDifference2", testDifference2), 197 | ("testDifference3", testDifference3), 198 | ("testDifference4", testDifference4), 199 | ("testDifference5", testDifference5), 200 | ("testDifference6", testDifference6), 201 | ("testDifference7", testDifference7), 202 | ("testReconstruct", testReconstruct), 203 | ("testApply", testApply), 204 | ] 205 | } 206 | -------------------------------------------------------------------------------- /Tests/SdiftTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !os(macOS) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(SdiftTests.allTests), 7 | ] 8 | } 9 | #endif --------------------------------------------------------------------------------