diff --git a/.gitignore b/.gitignore index 35b1b12..e60dc0c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,8 @@ profile *.moved-aside *.playground *.framework +DerivedData +Index +Build + +.build \ No newline at end of file diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..819e07a --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +5.0 diff --git a/Algorithm.podspec b/Algorithm.podspec index 8dbe19e..0c5a5cc 100644 --- a/Algorithm.podspec +++ b/Algorithm.podspec @@ -1,11 +1,12 @@ Pod::Spec.new do |s| s.name = 'Algorithm' - s.version = '1.0.8' + s.version = '3.1.1' + s.swift_version = '5.0' s.license = 'BSD-3-Clause' s.summary = 'A toolset for writing algorithms in Swift.' - s.homepage = 'http://cosmicmind.io' - s.social_media_url = 'https://www.facebook.com/graphkit' - s.authors = { 'CosmicMind, Inc.' => 'support@cosmicmind.io' } + s.homepage = 'http://cosmicmind.com' + s.social_media_url = 'https://www.facebook.com/cosmicmindcom' + s.authors = { 'CosmicMind, Inc.' => 'support@cosmicmind.com' } s.source = { :git => 'https://github.com/CosmicMind/Algorithm.git', :tag => s.version } s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' diff --git a/Algorithm.xcodeproj/project.pbxproj b/Algorithm.xcodeproj/project.pbxproj index b242e9a..375d13d 100644 --- a/Algorithm.xcodeproj/project.pbxproj +++ b/Algorithm.xcodeproj/project.pbxproj @@ -22,8 +22,8 @@ 65744CF51C554EDA0011C977 /* DoublyLinkedListNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE11C554EDA0011C977 /* DoublyLinkedListNode.swift */; }; 65744CF61C554EDA0011C977 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 65744CE21C554EDA0011C977 /* LICENSE */; }; 65744CF71C554EDA0011C977 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 65744CE21C554EDA0011C977 /* LICENSE */; }; - 65744CF81C554EDA0011C977 /* ProbableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* ProbableType.swift */; }; - 65744CF91C554EDA0011C977 /* ProbableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* ProbableType.swift */; }; + 65744CF81C554EDA0011C977 /* Probable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* Probable.swift */; }; + 65744CF91C554EDA0011C977 /* Probable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* Probable.swift */; }; 65744CFA1C554EDA0011C977 /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE41C554EDA0011C977 /* Queue.swift */; }; 65744CFB1C554EDA0011C977 /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE41C554EDA0011C977 /* Queue.swift */; }; 65744CFC1C554EDA0011C977 /* RedBlackNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65744CE51C554EDA0011C977 /* RedBlackNode.swift */; }; @@ -65,7 +65,7 @@ 65744D2A1C554F2E0011C977 /* Deque.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CDF1C554EDA0011C977 /* Deque.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D2B1C554F2E0011C977 /* DoublyLinkedList.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE01C554EDA0011C977 /* DoublyLinkedList.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D2C1C554F2E0011C977 /* DoublyLinkedListNode.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE11C554EDA0011C977 /* DoublyLinkedListNode.swift */; settings = {ATTRIBUTES = (Public, ); }; }; - 65744D2D1C554F2E0011C977 /* ProbableType.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* ProbableType.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + 65744D2D1C554F2E0011C977 /* Probable.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* Probable.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D2E1C554F2E0011C977 /* Queue.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE41C554EDA0011C977 /* Queue.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D2F1C554F2E0011C977 /* RedBlackNode.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE51C554EDA0011C977 /* RedBlackNode.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D301C554F2E0011C977 /* RedBlackTree.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE61C554EDA0011C977 /* RedBlackTree.swift */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -80,7 +80,7 @@ 65744D391C554F400011C977 /* Deque.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CDF1C554EDA0011C977 /* Deque.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D3A1C554F410011C977 /* DoublyLinkedList.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE01C554EDA0011C977 /* DoublyLinkedList.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D3B1C554F410011C977 /* DoublyLinkedListNode.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE11C554EDA0011C977 /* DoublyLinkedListNode.swift */; settings = {ATTRIBUTES = (Public, ); }; }; - 65744D3C1C554F410011C977 /* ProbableType.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* ProbableType.swift */; settings = {ATTRIBUTES = (Public, ); }; }; + 65744D3C1C554F410011C977 /* Probable.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE31C554EDA0011C977 /* Probable.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D3D1C554F410011C977 /* Queue.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE41C554EDA0011C977 /* Queue.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D3E1C554F410011C977 /* RedBlackNode.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE51C554EDA0011C977 /* RedBlackNode.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 65744D3F1C554F410011C977 /* RedBlackTree.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65744CE61C554EDA0011C977 /* RedBlackTree.swift */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -115,14 +115,14 @@ 65744CB91C554DDC0011C977 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65744CBE1C554DED0011C977 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65744CC61C554E370011C977 /* Algorithm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Algorithm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 65744CCF1C554E380011C977 /* Algorithm OSX Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Algorithm OSX Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 65744CCF1C554E380011C977 /* Algorithm macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Algorithm macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 65744CDD1C554EDA0011C977 /* Algorithm+Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Algorithm+Array.swift"; sourceTree = ""; }; 65744CDE1C554EDA0011C977 /* Algorithm+Set.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Algorithm+Set.swift"; sourceTree = ""; }; 65744CDF1C554EDA0011C977 /* Deque.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Deque.swift; sourceTree = ""; }; 65744CE01C554EDA0011C977 /* DoublyLinkedList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoublyLinkedList.swift; sourceTree = ""; }; 65744CE11C554EDA0011C977 /* DoublyLinkedListNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoublyLinkedListNode.swift; sourceTree = ""; }; 65744CE21C554EDA0011C977 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; - 65744CE31C554EDA0011C977 /* ProbableType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProbableType.swift; sourceTree = ""; }; + 65744CE31C554EDA0011C977 /* Probable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Probable.swift; sourceTree = ""; }; 65744CE41C554EDA0011C977 /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queue.swift; sourceTree = ""; }; 65744CE51C554EDA0011C977 /* RedBlackNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedBlackNode.swift; sourceTree = ""; }; 65744CE61C554EDA0011C977 /* RedBlackTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedBlackTree.swift; sourceTree = ""; }; @@ -185,6 +185,7 @@ 65744C9D1C554BA50011C977 /* Products */, ); sourceTree = ""; + usesTabs = 0; }; 65744C9D1C554BA50011C977 /* Products */ = { isa = PBXGroup; @@ -192,7 +193,7 @@ 65744C9C1C554BA50011C977 /* Algorithm.framework */, 65744CA61C554BA50011C977 /* Algorithm iOS Tests.xctest */, 65744CC61C554E370011C977 /* Algorithm.framework */, - 65744CCF1C554E380011C977 /* Algorithm OSX Tests.xctest */, + 65744CCF1C554E380011C977 /* Algorithm macOS Tests.xctest */, ); name = Products; sourceTree = ""; @@ -208,7 +209,7 @@ 65744CDF1C554EDA0011C977 /* Deque.swift */, 65744CE01C554EDA0011C977 /* DoublyLinkedList.swift */, 65744CE11C554EDA0011C977 /* DoublyLinkedListNode.swift */, - 65744CE31C554EDA0011C977 /* ProbableType.swift */, + 65744CE31C554EDA0011C977 /* Probable.swift */, 65744CE41C554EDA0011C977 /* Queue.swift */, 65744CE51C554EDA0011C977 /* RedBlackNode.swift */, 65744CE61C554EDA0011C977 /* RedBlackTree.swift */, @@ -251,7 +252,7 @@ 65744D2A1C554F2E0011C977 /* Deque.swift in Headers */, 65744D2B1C554F2E0011C977 /* DoublyLinkedList.swift in Headers */, 65744D2C1C554F2E0011C977 /* DoublyLinkedListNode.swift in Headers */, - 65744D2D1C554F2E0011C977 /* ProbableType.swift in Headers */, + 65744D2D1C554F2E0011C977 /* Probable.swift in Headers */, 65744D2E1C554F2E0011C977 /* Queue.swift in Headers */, 65744D2F1C554F2E0011C977 /* RedBlackNode.swift in Headers */, 65744D301C554F2E0011C977 /* RedBlackTree.swift in Headers */, @@ -274,7 +275,7 @@ 65744D391C554F400011C977 /* Deque.swift in Headers */, 65744D3A1C554F410011C977 /* DoublyLinkedList.swift in Headers */, 65744D3B1C554F410011C977 /* DoublyLinkedListNode.swift in Headers */, - 65744D3C1C554F410011C977 /* ProbableType.swift in Headers */, + 65744D3C1C554F410011C977 /* Probable.swift in Headers */, 65744D3D1C554F410011C977 /* Queue.swift in Headers */, 65744D3E1C554F410011C977 /* RedBlackNode.swift in Headers */, 65744D3F1C554F410011C977 /* RedBlackTree.swift in Headers */, @@ -325,9 +326,9 @@ productReference = 65744CA61C554BA50011C977 /* Algorithm iOS Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 65744CC51C554E370011C977 /* Algorithm OSX */ = { + 65744CC51C554E370011C977 /* Algorithm macOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 65744CD71C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm OSX" */; + buildConfigurationList = 65744CD71C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm macOS" */; buildPhases = ( 65744CC11C554E370011C977 /* Sources */, 65744CC21C554E370011C977 /* Frameworks */, @@ -338,14 +339,14 @@ ); dependencies = ( ); - name = "Algorithm OSX"; + name = "Algorithm macOS"; productName = "Algorithm OSX"; productReference = 65744CC61C554E370011C977 /* Algorithm.framework */; productType = "com.apple.product-type.framework"; }; - 65744CCE1C554E380011C977 /* Algorithm OSX Tests */ = { + 65744CCE1C554E380011C977 /* Algorithm macOS Tests */ = { isa = PBXNativeTarget; - buildConfigurationList = 65744CDA1C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm OSX Tests" */; + buildConfigurationList = 65744CDA1C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm macOS Tests" */; buildPhases = ( 65744CCB1C554E380011C977 /* Sources */, 65744CCC1C554E380011C977 /* Frameworks */, @@ -356,9 +357,9 @@ dependencies = ( 65744CD21C554E380011C977 /* PBXTargetDependency */, ); - name = "Algorithm OSX Tests"; + name = "Algorithm macOS Tests"; productName = "Algorithm OSXTests"; - productReference = 65744CCF1C554E380011C977 /* Algorithm OSX Tests.xctest */; + productReference = 65744CCF1C554E380011C977 /* Algorithm macOS Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -368,29 +369,34 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = "CosmicMind, Inc."; TargetAttributes = { 65744C9B1C554BA50011C977 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1020; }; 65744CA51C554BA50011C977 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1020; }; 65744CC51C554E370011C977 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1020; }; 65744CCE1C554E380011C977 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 1020; }; }; }; buildConfigurationList = 65744C961C554BA50011C977 /* Build configuration list for PBXProject "Algorithm" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 65744C921C554BA50011C977; productRefGroup = 65744C9D1C554BA50011C977 /* Products */; @@ -398,9 +404,9 @@ projectRoot = ""; targets = ( 65744C9B1C554BA50011C977 /* Algorithm iOS */, - 65744CC51C554E370011C977 /* Algorithm OSX */, + 65744CC51C554E370011C977 /* Algorithm macOS */, 65744CA51C554BA50011C977 /* Algorithm iOS Tests */, - 65744CCE1C554E380011C977 /* Algorithm OSX Tests */, + 65744CCE1C554E380011C977 /* Algorithm macOS Tests */, ); }; /* End PBXProject section */ @@ -454,7 +460,7 @@ 65744CF41C554EDA0011C977 /* DoublyLinkedListNode.swift in Sources */, 65744CFE1C554EDA0011C977 /* RedBlackTree.swift in Sources */, 65744CF01C554EDA0011C977 /* Deque.swift in Sources */, - 65744CF81C554EDA0011C977 /* ProbableType.swift in Sources */, + 65744CF81C554EDA0011C977 /* Probable.swift in Sources */, 65744CF21C554EDA0011C977 /* DoublyLinkedList.swift in Sources */, 65744D041C554EDA0011C977 /* SortedMultiSet.swift in Sources */, ); @@ -492,7 +498,7 @@ 65744CF51C554EDA0011C977 /* DoublyLinkedListNode.swift in Sources */, 65744CFF1C554EDA0011C977 /* RedBlackTree.swift in Sources */, 65744CF11C554EDA0011C977 /* Deque.swift in Sources */, - 65744CF91C554EDA0011C977 /* ProbableType.swift in Sources */, + 65744CF91C554EDA0011C977 /* Probable.swift in Sources */, 65744CF31C554EDA0011C977 /* DoublyLinkedList.swift in Sources */, 65744D051C554EDA0011C977 /* SortedMultiSet.swift in Sources */, ); @@ -525,7 +531,7 @@ }; 65744CD21C554E380011C977 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 65744CC51C554E370011C977 /* Algorithm OSX */; + target = 65744CC51C554E370011C977 /* Algorithm macOS */; targetProxy = 65744CD11C554E380011C977 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -535,17 +541,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -574,6 +591,8 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -584,17 +603,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -615,6 +645,9 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -626,6 +659,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -633,10 +667,11 @@ INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "io.cosmicmind.Algorithm-iOS"; + PRODUCT_BUNDLE_IDENTIFIER = com.cosmicmind.Algorithm; PRODUCT_NAME = Algorithm; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -644,6 +679,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -651,9 +687,10 @@ INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "io.cosmicmind.Algorithm-iOS"; + PRODUCT_BUNDLE_IDENTIFIER = com.cosmicmind.Algorithm; PRODUCT_NAME = Algorithm; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -666,6 +703,7 @@ PRODUCT_BUNDLE_IDENTIFIER = io.cosmicmind.AlgorithmTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -677,6 +715,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = io.cosmicmind.AlgorithmTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -684,7 +723,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -694,11 +733,12 @@ INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "io.cosmicmind.Algorithm-OSX"; + PRODUCT_BUNDLE_IDENTIFIER = com.cosmicmind.Algorithm; PRODUCT_NAME = Algorithm; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -706,7 +746,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -716,10 +756,11 @@ INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "io.cosmicmind.Algorithm-OSX"; + PRODUCT_BUNDLE_IDENTIFIER = com.cosmicmind.Algorithm; PRODUCT_NAME = Algorithm; SDKROOT = macosx; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -736,6 +777,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -751,6 +793,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "io.cosmicmind.Algorithm-OSXTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -784,7 +827,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 65744CD71C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm OSX" */ = { + 65744CD71C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm macOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 65744CD81C554E380011C977 /* Debug */, @@ -793,7 +836,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 65744CDA1C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm OSX Tests" */ = { + 65744CDA1C554E380011C977 /* Build configuration list for PBXNativeTarget "Algorithm macOS Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( 65744CDB1C554E380011C977 /* Debug */, diff --git a/Algorithm.xcodeproj/xcshareddata/xcschemes/Algorithm iOS.xcscheme b/Algorithm.xcodeproj/xcshareddata/xcschemes/Algorithm iOS.xcscheme index 1be96d7..a3c2ec5 100644 --- a/Algorithm.xcodeproj/xcshareddata/xcschemes/Algorithm iOS.xcscheme +++ b/Algorithm.xcodeproj/xcshareddata/xcschemes/Algorithm iOS.xcscheme @@ -1,6 +1,6 @@ @@ -33,8 +33,8 @@ @@ -44,7 +44,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "65744CC51C554E370011C977" BuildableName = "Algorithm.framework" - BlueprintName = "Algorithm OSX" + BlueprintName = "Algorithm macOS" ReferencedContainer = "container:Algorithm.xcodeproj"> @@ -66,7 +66,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "65744CC51C554E370011C977" BuildableName = "Algorithm.framework" - BlueprintName = "Algorithm OSX" + BlueprintName = "Algorithm macOS" ReferencedContainer = "container:Algorithm.xcodeproj"> @@ -84,7 +84,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "65744CC51C554E370011C977" BuildableName = "Algorithm.framework" - BlueprintName = "Algorithm OSX" + BlueprintName = "Algorithm macOS" ReferencedContainer = "container:Algorithm.xcodeproj"> diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..64f0712 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +## 3.1.1 + +* Added installation instructions to README. + +## 2.1.1 + +* Updated for Swift 4.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5dff6e4..ad3fdd0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,7 +34,7 @@ CosmicMind takes security seriously. If you discover a security issue, please bring it to our attention right away! Please **DO NOT** file a public issue, -instead send your report privately to . +instead send your report privately to . This will help ensure that any vulnerabilities that _are_ found can be [disclosed responsibly](http://en.wikipedia.org/wiki/Responsible_disclosure) to any affected parties. diff --git a/Examples/Algorithm.xcworkspace/contents.xcworkspacedata b/Examples/Algorithm.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index b135bf9..0000000 --- a/Examples/Algorithm.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/LICENSE.md b/LICENSE.md index f2cdb9f..ae5f098 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,16 +1,22 @@ -Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . All rights reserved. +The MIT License (MIT) -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Copyright (C) 2019, CosmicMind, Inc. . +All rights reserved. -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -* 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. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -* Neither the name of Algorithm nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..090a41f --- /dev/null +++ b/Package.swift @@ -0,0 +1,30 @@ +// swift-tools-version:4.2 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Algorithm", + products: [ + // Products define the executables and libraries produced by a package, and make them visible to other packages. + .library( + name: "Algorithm", + targets: ["Algorithm"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "Algorithm", + dependencies: [], + path: "Sources"), + .testTarget( + name: "AlgorithmTests", + dependencies: ["Algorithm"], + path: "Tests"), + ] +) diff --git a/README.md b/README.md index c5c3e2b..e2348af 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,33 @@ -![CosmicMind](http://www.cosmicmind.io/algorithm/index/images/AlgorithmIcon.png) +![Algorithm](http://www.cosmicmind.com/algorithm/github/algorithm-logo.png) ## Welcome to Algorithm -Algorithm is a collection of data structures that are empowered by a probability toolset. +Algorithm is a library of tools that is used to create intelligent applications. -Algorithm's architecture is designed for beginners and professionals. Its robust API requires no setup and is ready for the simplest and most extensive applications. +## Features + +- [x] Probability Tools +- [x] Expected Value +- [x] Programmable Probability Blocks +- [x] Array Extensions +- [x] Set Extensions + +## Data Structures + +- [x] DoublyLinkedList +- [x] Stack +- [x] Queue +- [x] Deque +- [x] RedBlackTree +- [x] SortedSet +- [x] SortedMultiSet +- [x] SortedDictionary +- [x] SortedMultiDictionary ## Requirements * iOS 8.0+ / Mac OS X 10.9+ -* Xcode 7.3+ +* Xcode 8.0+ ## Communication @@ -21,28 +39,76 @@ Algorithm's architecture is designed for beginners and professionals. Its robust ## Installation -> **Embedded frameworks require a minimum deployment target of iOS 8 or OS X Mavericks (10.9).** +> **Embedded frameworks require a minimum deployment target of iOS 8.** > - [Download Algorithm](https://github.com/CosmicMind/Algorithm/archive/master.zip) -Visit the [Installation](https://github.com/CosmicMind/Algorithm/wiki/Installation) page to learn how to install Algorithm using [CocoaPods](http://cocoapods.org) and [Carthage](https://github.com/Carthage/Carthage). +## CocoaPods + +[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: + +```bash +$ gem install cocoapods +``` + +To integrate Algorithm's core features into your Xcode project using CocoaPods, specify it in your `Podfile`: + +```ruby +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' +use_frameworks! + +pod 'Algorithm', '~> 3.1.0' +``` + +Then, run the following command: + +```bash +$ pod install +``` + +## Carthage + +Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. + +You can install Carthage with Homebrew using the following command: + +```bash +$ brew update +$ brew install carthage +``` +To integrate Algorithm into your Xcode project using Carthage, specify it in your Cartfile: + +```bash +github "CosmicMind/Algorithm" +``` + +Run `carthage update` to build the framework and drag the built `Algorithm.framework` into your Xcode project. ## Changelog Algorithm is a growing project and will encounter changes throughout its development. It is recommended that the [Changelog](https://github.com/CosmicMind/Algorithm/wiki/Changelog) be reviewed prior to updating versions. -## A Tour +# Samples -* [Probability](#probability) -* [ExpectedValue](#expectedvalue) -* [DoublyLinkedList](#doublylinkedlist) -* [Stack](#stack) -* [Queue](#queue) -* [Deque](#deque) -* [RedBlackTree](#redblacktree) -* [SortedSet](#sortedset) -* [SortedMultiSet](#sortedmultiset) -* [SortedDictionary](#sorteddictionary) -* [SortedMultiDictionary](#sortedmultidictionary) +The following are samples to see how Algorithm may be used within your applications. + +* Visit the [Samples](https://github.com/CosmicMind/Samples) repo to see example projects using Algorithm. + +- [Samples](#samples) + - [Probability](#probability) + - [Basic Probability](#basic-probability) + - [Conditional Probability](#conditional-probability) + - [Expected Value](#expected-value) + - [DoublyLinkedList](#doublylinkedlist) + - [Stack](#stack) + - [Queue](#queue) + - [Deque](#deque) + - [RedBlackTree](#redblacktree) + - [SortedSet](#sortedset) + - [SortedMultiSet](#sortedmultiset) + - [SortedDictionary](#sorteddictionary) + - [SortedMultiDictionary](#sortedmultidictionary) + - [License](#license) ## Probability @@ -54,8 +120,11 @@ Each data structure within Algorithm is equipped with probability tools. For example, determining the probability of rolling a 3 using a die of 6 numbers. ```swift -let die: Array = Array(arrayLiteral: 1, 2, 3, 4, 5, 6) -print(die.probabilityOf(3)) // Output: 0.166666666666667 +let die = [Int](arrayLiteral: 1, 2, 3, 4, 5, 6) + +if 0.1 < die.probability(of: 3) + // Do something ... +} ``` #### Conditional Probability @@ -63,18 +132,14 @@ print(die.probabilityOf(3)) // Output: 0.166666666666667 For conditional probabilities that require a more complex calculation, use block statements. ```swift -let die: Array = Array(arrayLiteral: 1, 2, 3, 4, 5, 6) - -let probabilityOfX: Double = die.probabilityOf { (number: Int) in - if 5 < number || 0 == number % 3 { - // Do more. - return true - } - return false +let die = [Int](arrayLiteral: 1, 2, 3, 4, 5, 6) + +let pOfX = die.probability { (number) in + return 5 < number || 0 == number % 3 } -if 0.33 < probabilityOfX { - // Do something. +if 0.33 < pOfX { + // Do something ... } ``` @@ -84,8 +149,11 @@ if 0.33 < probabilityOfX { The expected value of rolling a 3 or 6 with 100 trials using a die of 6 numbers. ```swift -let die: Array = Array(arrayLiteral: 1, 2, 3, 4, 5, 6) -print(die.expectedValueOf(100, elements: 3, 6)) // Output: 33.3333333333333 +let die = [Int](arrayLiteral: 1, 2, 3, 4, 5, 6) + +if 20 < die.expectedValue(trials: 100, for: 3, 6) { + // Do something ... +} ``` @@ -94,29 +162,29 @@ print(die.expectedValueOf(100, elements: 3, 6)) // Output: 33.3333333333333 The DoublyLinkedList data structure is excellent for large growing collections of data. Below is an example of its usage. ```swift -let listA: DoublyLinkedList = DoublyLinkedList() -listA.insertAtFront(3) -listA.insertAtFront(2) -listA.insertAtFront(1) +var listA = DoublyLinkedList() + +listA.insert(atFront: 3) +listA.insert(atFront: 2) +listA.insert(atFront: 1) + +var listB = DoublyLinkedList() -let listB: DoublyLinkedList = DoublyLinkedList() -listB.insertAtBack(4) -listB.insertAtBack(5) -listB.insertAtBack(6) +listB.insert(atBack: 4) +listB.insert(atBack: 5) +listB.insert(atBack: 6) -let listC: DoublyLinkedList = listA + listB +var listC = listA + listB listC.cursorToFront() -repeat { - print(listC.cursor) -} while nil != listC.next -// Output: -// 1 -// 2 -// 3 -// 4 -// 5 -// 6 + +var value = listC.cursor + +while nil != value { + // Do something ... + + value = listC.next() +} ``` @@ -125,18 +193,17 @@ repeat { The Stack data structure is a container of objects that are inserted and removed according to the last-in-first-out (LIFO) principle. Below is an example of its usage. ```swift -let stack: Stack = Stack() +var stack = Stack() + stack.push(1) stack.push(2) stack.push(3) while !stack.isEmpty { - print(stack.pop()) + let value = stack.pop() + + // Do something ... } -// Output: -// 3 -// 2 -// 1 ``` @@ -145,18 +212,17 @@ while !stack.isEmpty { The Queue data structure is a container of objects that are inserted and removed according to the first-in-first-out (FIFO) principle. Below is an example of its usage. ```swift -let queue: Queue = Queue() +var queue = Queue() + queue.enqueue(1) queue.enqueue(2) queue.enqueue(3) while !queue.isEmpty { - print(queue.dequeue()) + let value = queue.dequeue() + + // Do something ... } -// Output: -// 1 -// 2 -// 3 ``` @@ -165,31 +231,27 @@ while !queue.isEmpty { The Deque data structure is a container of objects that are inserted and removed according to the first-in-first-out (FIFO) and last-in-first-out (LIFO) principle. Essentially, a Deque is a Stack and Queue combined. Below are examples of its usage. ```swift -let dequeA: Deque = Deque() -dequeA.insertAtBack(1) -dequeA.insertAtBack(2) -dequeA.insertAtBack(3) +var dequeA = Deque() +dequeA.insert(atBack: 1) +dequeA.insert(atBack: 2) +dequeA.insert(atBack: 3) while !dequeA.isEmpty { - print(dequeA.removeAtFront()) + let value = dequeA.removeAtFront() + + // Do something ... } -// Output: -// 1 -// 2 -// 3 -let dequeB: Deque = Deque() -dequeB.insertAtBack(4) -dequeB.insertAtBack(5) -dequeB.insertAtBack(6) +var dequeB = Deque() +dequeB.insert(atBack: 4) +dequeB.insert(atBack: 5) +dequeB.insert(atBack: 6) while !dequeB.isEmpty { - print(dequeB.removeAtBack()) + let value = dequeB.removeAtFront() + + // Do something ... } -// Output: -// 6 -// 5 -// 4 ``` @@ -198,14 +260,17 @@ while !dequeB.isEmpty { A RedBlackTree is a Balanced Binary Search Tree that maintains insert, remove, update, and search operations in a complexity of O(logn). The following implementation of a RedBlackTree also includes an order-statistic, which allows the data structure to be accessed using subscripts like an array or dictionary. RedBlackTrees may store unique keys or non-unique key values. Below is an example of its usage. ```swift -let rbA: RedBlackTree = RedBlackTree(uniqueKeys: true) +var ages = RedBlackTree(uniqueKeys: true) + +ages.insert(value: 16, for: "Sarah") +ages.insert(value: 12, for: "Peter") +ages.insert(value: 23, for: "Alex") + +let node = ages[1] -for var i: Int = 1000; 0 < i; --i { - rbA.insert(1, value: 1) - rbA.insert(2, value: 2) - rbA.insert(3, value: 3) +if "Peter" == node.key { + // Do something ... } -print(rbA.count) // Output: 3 ``` @@ -214,34 +279,32 @@ print(rbA.count) // Output: 3 SortedSets are a powerful data structure for algorithm and analysis design. Elements within a SortedSet are unique and insert, remove, and search operations have a complexity of O(logn). The following implementation of a SortedSet also includes an order-statistic, which allows the data structure to be accessed using an index subscript like an array. Below are examples of its usage. ```swift -let setA: SortedSet = SortedSet(elements: 1, 2, 3) // Sorted: [1, 2, 3] -let setB: SortedSet = SortedSet(elements: 4, 3, 6) // Sorted: [3, 4, 6] - -let setC: SortedSet = SortedSet(elements: 7, 1, 2) // Sorted: [1, 2, 7] -let setD: SortedSet = SortedSet(elements: 1, 7) // Sorted: [1, 7] - -let setE: SortedSet = SortedSet(elements: 1, 6, 7) // Sorted: [1, 6, 7] +let setA = SortedSet(elements: 1, 2, 3) +let setB = SortedSet(elements: 4, 3, 6) +let setC = SortedSet(elements: 7, 1, 2) +let setD = SortedSet(elements: 1, 7) +let setE = SortedSet(elements: 1, 6, 7) // Union. -print((setA + setB).count) // Output: 5 -print(setA.union(setB).count) // Output: 5 +setA + setB +setA.union(setB) -// Intersect. -print(setC.intersect(setD).count) // Output: 2 +// Intersection. +setC.intersection(setD) // Subset. -print(setD < setC) // true -print(setD.isSubsetOf(setC)) // true +setD < setC +setD.isSubset(of: setC) // Superset. -print(setD > setC) // false -print(setD.isSupersetOf(setC)) // false +setD > setC +setD.isSuperset(of: setC) // Contains. -print(setE.contains(setA.first!)) // true +setE.contains(setA.first!) // Probability. -print(setE.probabilityOf(setA.first!, setA.last!)) // 0.333333333333333 +setE.probability(of: setA.first!, setA.last!) ``` @@ -264,29 +327,42 @@ struct Student { var name: String } -let dict: SortedMultiDictionary = SortedMultiDictionary() +let sarah = Student(name: "Sarah") +let peter = Student(name: "Peter") +let alex = Student(name: "Alex") + +var students = SortedMultiDictionary() + +students.insert(value: sarah, for: sarah.name) +students.insert(value: peter, for: peter.name) +students.insert(value: alex, for: alex.name) -// Do something with an alphabetically SortedMultiDictionary of Student structs. for student in students { - dict.insert(student.name, value: student) + // Do something ... } ``` ## License -Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +The MIT License (MIT) -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. +Copyright (C) 2019, CosmicMind, Inc. . +All rights reserved. -* 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. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -* Neither the name of Algorithm nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -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. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Sources/Algorithm+Array.swift b/Sources/Algorithm+Array.swift index ff3aa1c..5f69e3c 100644 --- a/Sources/Algorithm+Array.swift +++ b/Sources/Algorithm+Array.swift @@ -1,117 +1,140 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ extension Array where Element: Equatable { - mutating func removeObject(object: Element) -> Element? { - if let v: Int = indexOf(object) { - return removeAtIndex(v) - } - return nil - } - - mutating func removeObjects(objects: Element...) { - removeObjects(objects) - } - - mutating func removeObjects(objects: Array) { - for x in objects { - removeObject(x) - } - } -} - -extension Array : ProbableType { - /** - The instance count of elements. - */ - public func countOf(elements: Element...) -> Int { - return countOf(elements) - } - - /** - The instance count of elements. - */ - public func countOf(elements: Array) -> Int { - var c: Int = 0 - for v in elements { - for x in self { - if v == x as! Element { - c += 1 - } - } - } - return c - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Element...) -> Double { - return probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Array) -> Double { - return 0 == count ? 0 : Double(countOf(elements)) / Double(count) - } - - /** - The probability of elements. - */ - public func probabilityOf(block: (element: Element) -> Bool) -> Double { - if 0 == count { - return 0 - } - - var c: Int = 0 - for x in self { - if block(element: x) { - c += 1 - } - } - return Double(c) / Double(count) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Element...) -> Double { - return expectedValueOf(trials, elements: elements) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Array) -> Double { - return Double(trials) * probabilityOf(elements) - } + /** + Removes a given Element from an Array if it exists. + - Parameter object: An Element. + - Returns: An optional Element if the removed + element exists. + */ + @discardableResult + mutating func remove(object: Element) -> Element? { + return firstIndex(of: object).map { self.remove(at: $0) } + } + + /** + Removes a list of given Elements from an Array if + they exists. + - Parameter objects: A list of Elements. + */ + mutating func remove(objects: Element...) { + remove(objects: objects) + } + + /** + Removes an Array of given Elements from an Array if + they exists. + - Parameter objects: An Array of Elements. + */ + mutating func remove(objects: [Element]) { + objects.forEach { + self.remove(object: $0) + } + } + + /** + The total count for the given Elements. + - Parameter of elements: A list of Elements. + - Returns: An Int. + */ + public func count(of elements: Element...) -> Int { + return count(of: elements) + } + + /** + The total count for the given Elements. + - Parameter of elements: An Array of Elements. + - Returns: An Int. + */ + public func count(of elements: [Element]) -> Int { + + var c = 0 + for e in elements { + for x in self where e == x { + c += 1 + } + } + return c + } + + /** + The probability of getting the given Elements. + - Parameter of elements: A list of Elements. + - Returns: A Double. + */ + public func probability(of elements: Element...) -> Double { + return probability(of: elements) + } + + /** + The probability of getting the given Elements. + - Parameter of elements: An Array of Elements. + - Returns: A Double. + */ + public func probability(of elements: [Element]) -> Double { + return 0 < count ? Double(count(of: elements)) / Double(count) : 0 + } + + /** + A probability method that uses a block to determine the member state of a condition. + - Parameter of elements: A list of Elements. + - Returns: A Double. + */ + public func probability(execute block: @escaping (Element) -> Bool) -> Double { + guard 0 < count else { + return 0 + } + + var c = 0 + for e in self { + if block(e) { + c += 1 + } + } + + return Double(c) / Double(count) + } + + /** + Calculates the expected value of elements based on a given number of trials. + - Parameter trials: Number of trials. + - Parameter elements: A list of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for elements: Element...) -> Double { + return expectedValue(trials: trials, for: elements) + } + + /** + Calculates the expected value of elements based on a given number of trials. + - Parameter trials: Number of trials. + - Parameter elements: An Array of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for elements: [Element]) -> Double { + return Double(trials) * probability(of: elements) + } } diff --git a/Sources/Algorithm+Set.swift b/Sources/Algorithm+Set.swift index bf195b9..dac8904 100644 --- a/Sources/Algorithm+Set.swift +++ b/Sources/Algorithm+Set.swift @@ -1,98 +1,110 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -extension Set : ProbableType { - /** - The instance count of elements. - */ - public func countOf(elements: Element...) -> Int { - return countOf(elements) - } - - /** - The instance count of elements. - */ - public func countOf(elements: Array) -> Int { - var c: Int = 0 - for v in elements { - for x in self { - if v == x as! Element { - c += 1 - } - } - } - return c - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Element...) -> Double { - return probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Array) -> Double { - return 0 == count ? 0 : Double(countOf(elements)) / Double(count) - } - - /** - The probability of elements. - */ - public func probabilityOf(block: (element: Element) -> Bool) -> Double { - if 0 == count { - return 0 - } - - var c: Int = 0 - for x in self { - if block(element: x) { - c += 1 - } - } - return Double(c) / Double(count) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Element...) -> Double { - return expectedValueOf(trials, elements: elements) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Array) -> Double { - return Double(trials) * probabilityOf(elements) - } +extension Set: Probable { + /** + The total count for the given Elements. + - Parameter of elements: A list of Elements. + - Returns: An Int. + */ + public func count(of elements: Element...) -> Int { + return count(of: elements) + } + + /** + The total count for the given Elements. + - Parameter of elements: An Array of Elements. + - Returns: An Int. + */ + public func count(of elements: [Element]) -> Int { + var c = 0 + for e in elements { + for x in self { + if e == x { + c += 1 + } + } + } + return c + } + + /** + The probability of getting the given Elements. + - Parameter of elements: A list of Elements. + - Returns: A Double. + */ + public func probability(of elements: Element...) -> Double { + return probability(of: elements) + } + + /** + The probability of getting the given Elements. + - Parameter of elements: An Array of Elements. + - Returns: A Double. + */ + public func probability(of elements: [Element]) -> Double { + return 0 < count ? Double(count(of: elements)) / Double(count) : 0 + } + + /** + A probability method that uses a block to determine the member state of a condition. + - Parameter of elements: A list of Elements. + - Returns: A Double. + */ + public func probability(of block: @escaping (Element) -> Bool) -> Double { + guard 0 < count else { + return 0 + } + + var c = 0 + for e in self { + if block(e) { + c += 1 + } + } + + return Double(c) / Double(count) + } + + /** + Calculates the expected value of elements based on a given number of trials. + - Parameter trials: Number of trials. + - Parameter elements: A list of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for elements: Element...) -> Double { + return expectedValue(trials: trials, for: elements) + } + + /** + Calculates the expected value of elements based on a given number of trials. + - Parameter trials: Number of trials. + - Parameter elements: An Array of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for elements: [Element]) -> Double { + return Double(trials) * probability(of: elements) + } } diff --git a/Sources/Algorithm.h b/Sources/Algorithm.h index 8f08464..f8df465 100644 --- a/Sources/Algorithm.h +++ b/Sources/Algorithm.h @@ -1,31 +1,26 @@ /* - * Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: + * The MIT License (MIT) * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. * - * * 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. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * * Neither the name of Algorithm nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * 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. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ #import diff --git a/Sources/Deque.swift b/Sources/Deque.swift index bd1ccc0..44ee648 100644 --- a/Sources/Deque.swift +++ b/Sources/Deque.swift @@ -1,166 +1,160 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ - -public class Deque : CustomStringConvertible, SequenceType { - public typealias Generator = AnyGenerator - - /** - :name: list - :description: Underlying element structure. - - returns: DoublyLinkedList - */ - private var list: DoublyLinkedList - - /** - :name: count - :description: Total number of items in the Deque. - - returns: Int - */ - public var count: Int { - return list.count - } - - /** - :name: front - :description: Get the element at the front of the Deque - and do not remove it. - - returns: Element? - */ - public var front: Element? { - return list.front - } - - /** - :name: back - :description: Get the element at the back of the Deque - and do not remove it. - - returns: Element? - */ - public var back: Element? { - return list.back - } - - /** - :name: isEmpty - :description: A boolean of whether the Deque is empty. - - returns: Bool - */ - public var isEmpty: Bool { - return list.isEmpty - } - - /** - :name: description - :description: Conforms to the Printable Protocol. - - returns: String - */ - public var description: String { - return "Deque" + list.internalDescription - } - - /** - :name: init - :description: Constructor. - */ - public init() { - list = DoublyLinkedList() - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes. - // :returns: Deque.Generator - // - public func generate() -> Deque.Generator { - return list.generate() - } - - /** - :name: insertAtFront - :description: Insert a new element at the front of the Deque. - */ - public func insertAtFront(element: Element) { - list.insertAtFront(element) - } - - /** - :name: removeAtFront - :description: Get the element at the front of the Deque - and remove it. - - returns: Element? - */ - public func removeAtFront() -> Element? { - return list.removeAtFront() - } - - /** - :name: insertAtBack - :description: Insert a new element at the back of the Deque. - */ - public func insertAtBack(element: Element) { - list.insertAtBack(element) - } - - /** - :name: removeAtBack - :description: Get the element at the back of the Deque - and remove it. - - returns: Element? - */ - public func removeAtBack() -> Element? { - return list.removeAtBack() - } - - /** - :name: removeAll - :description: Remove all elements from the Deque. - */ - public func removeAll() { - list.removeAll() - } + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +public struct Deque: CustomStringConvertible, Sequence { + public typealias Iterator = AnyIterator + + /** + :name: list + :description: Underlying element structure. + - returns: DoublyLinkedList + */ + private var list: DoublyLinkedList + + /** + :name: count + :description: Total number of items in the Deque. + - returns: Int + */ + public var count: Int { + return list.count + } + + /** + :name: front + :description: Get the element at the front of the Deque + and do not remove it. + - returns: Element? + */ + public var front: Element? { + return list.front + } + + /** + :name: back + :description: Get the element at the back of the Deque + and do not remove it. + - returns: Element? + */ + public var back: Element? { + return list.back + } + + /** + :name: isEmpty + :description: A boolean of whether the Deque is empty. + - returns: Bool + */ + public var isEmpty: Bool { + return list.isEmpty + } + + /** + :name: description + :description: Conforms to the Printable Protocol. + - returns: String + */ + public var description: String { + return list.description + } + + /** + :name: init + :description: Constructor. + */ + public init() { + list = DoublyLinkedList() + } + + /** + Conforms to the SequenceType Protocol. Returns the next value + in the sequence of nodes. + - Returns: A Deque.Iterator. + */ + public func makeIterator() -> Deque.Iterator { + return list.makeIterator() + } + + /** + :name: insertAtFront + :description: Insert a new element at the front of the Deque. + */ + mutating public func insert(atFront element: Element) { + list.insert(atFront: element) + } + + /** + :name: removeAtFront + :description: Get the element at the front of the Deque + and remove it. + - returns: Element? + */ + mutating public func removeAtFront() -> Element? { + return list.removeAtFront() + } + + /** + :name: insertAtBack + :description: Insert a new element at the back of the Deque. + */ + mutating public func insert(atBack element: Element) { + list.insert(atBack: element) + } + + /** + :name: removeAtBack + :description: Get the element at the back of the Deque + and remove it. + - returns: Element? + */ + mutating public func removeAtBack() -> Element? { + return list.removeAtBack() + } + + /** + :name: removeAll + :description: Remove all elements from the Deque. + */ + mutating public func removeAll() { + list.removeAll() + } } public func +(lhs: Deque, rhs: Deque) -> Deque { - let d: Deque = Deque() - for x in lhs { - d.insertAtBack(x!) - } - for x in rhs { - d.insertAtBack(x!) - } - return d + var d = Deque() + for x in lhs { + d.insert(atBack: x) + } + for x in rhs { + d.insert(atBack: x) + } + return d } -public func +=(lhs: Deque, rhs: Deque) { - for x in rhs { - lhs.insertAtBack(x!) - } +public func +=(lhs: inout Deque, rhs: Deque) { + for x in rhs { + lhs.insert(atBack: x) + } } diff --git a/Sources/DoublyLinkedList.swift b/Sources/DoublyLinkedList.swift index 7d1a76f..6455c04 100644 --- a/Sources/DoublyLinkedList.swift +++ b/Sources/DoublyLinkedList.swift @@ -1,395 +1,353 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -public class DoublyLinkedList : CustomStringConvertible, SequenceType { - public typealias Generator = AnyGenerator - - /** - :name: head - :description: First node in the list. - - returns: DoublyLinkedListNode? - */ - private var head: DoublyLinkedListNode? - - /** - :name: tail - :description: Last node in list. - - returns: DoublyLinkedListNode? - */ - private var tail: DoublyLinkedListNode? - - /** - :name: current - :description: Current cursor position when iterating. - - returns: DoublyLinkedListNode? - */ - private var current: DoublyLinkedListNode? - - /** - :name: count - :description: Number of nodes in DoublyLinkedList. - - returns: Int - */ - public private(set) var count: Int - - /** - :name: internalDescription - :description: Returns a String with only the node data for all - nodes in the DoublyLinkedList. - - returns: String - */ - internal var internalDescription: String { - var output: String = "(" - var c: Int = 0 - var x: DoublyLinkedListNode? = head - while nil !== x { - output += "\(x)" - c += 1 - if c != count { - output += ", " - } - x = x!.next - } - output += ")" - return output - } - - /** - :name: description - :description: Conforms to Printable Protocol. - - returns: String - */ - public var description: String { - return "DoublyLinkedList" + internalDescription - } - - /** - :name: front - :description: Retrieves the data at first node of the DoublyLinkedList. - - returns: Element? - */ - public var front: Element? { - return head?.element - } - - /** - :name: back - :description: Retrieves the element at the back node of teh DoublyLinkedList. - - returns: Element? - */ - public var back: Element? { - return tail?.element - } - - /** - :name: cursor - :description: Retrieves the element at the current iterator position - in the DoublyLinkedList. - - returns: Element? - */ - public var cursor: Element? { - return current?.element - } - - /** - :name: next - :description: Retrieves the element at the poistion after the - current cursor poistion. Also moves the cursor - to that node. - - returns: Element? - */ - public var next: Element? { - current = current?.next - return current?.element - } - - /** - :name: previous - :description: Retrieves the element at the poistion before the - current cursor poistion. Also moves the cursor - to that node. - - returns: Element? - */ - public var previous: Element? { - current = current?.previous - return current?.element - } - - /** - :name: isEmpty - :description: A boolean of whether the DoublyLinkedList is empty. - - returns: Bool - */ - public var isEmpty: Bool { - return 0 == count - } - - /** - :name: isCursorAtBack - :description: A boolean of whether the cursor has reached - the back of the DoublyLinkedList. - - returns: Bool - */ - public var isCursorAtBack: Bool { - return nil === current - } - - /** - :name: isCursorAtFront - :description: A boolean of whether the cursor has reached - the front of the DoublyLinkedList. - - returns: Bool - */ - public var isCursorAtFront: Bool { - return nil === current - } - - /** - :name: init - :description: Constructor. - */ - public init() { - count = 0 - reset() - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes. - // :returns: DoublyLinkedList.Generator - // - public func generate() -> DoublyLinkedList.Generator { - cursorToFront() - return AnyGenerator { - if !self.isCursorAtBack { - let element: Element? = self.cursor - self.next - return element - } - return nil - } - } - - /** - :name: removeAll - :description: Removes all nodes from the DoublyLinkedList. - */ - public func removeAll() { - while !isEmpty { - removeAtFront() - } - } - - /** - :name: insertAtFront - :description: Insert a new element at the front - of the DoublyLinkedList. - */ - public func insertAtFront(element: Element) { - var z: DoublyLinkedListNode - if 0 == count { - z = DoublyLinkedListNode(next: nil, previous: nil, element: element) - tail = z - } else { - z = DoublyLinkedListNode(next: head, previous: nil, element: element) - head!.previous = z - } - head = z - count += 1 - if 1 == count { - current = head - } else if head === current { - current = head!.next - } - } - - /** - :name: removeAtFront - :description: Remove the element at the front of the DoublyLinkedList - and return the element at the poistion. - - returns: Element? - */ - public func removeAtFront() -> Element? { - if 0 == count { - return nil - } - let element: Element? = head!.element - count -= 1 - if 0 == count { - reset() - } else { - head = head!.next - } - return element - } - - /** - :name: insertAtBack - :description: Insert a new element at the back - of the DoublyLinkedList. - */ - public func insertAtBack(element: Element) { - var z: DoublyLinkedListNode - if 0 == count { - z = DoublyLinkedListNode(next: nil, previous: nil, element: element) - head = z - } else { - z = DoublyLinkedListNode(next: nil, previous: tail, element: element) - tail!.next = z - } - tail = z - count += 1 - if 1 == count { - current = tail - } else if tail === current { - current = tail!.previous - } - } - - /** - :name: removeAtBack - :description: Remove the element at the back of the DoublyLinkedList - and return the element at the poistion. - - returns: Element? - */ - public func removeAtBack() -> Element? { - if 0 == count { - return nil - } - let element: Element? = tail!.element - count -= 1 - if 0 == count { - reset() - } else { - tail = tail!.previous - } - return element - } - - /** - :name: cursorToFront - :description: Move the cursor to the front of the DoublyLinkedList. - */ - public func cursorToFront() { - current = head - } - - /** - :name: cursorToBack - :description: Move the cursor to the back of the DoublyLinkedList. - */ - public func cursorToBack() { - current = tail - } - - /** - :name: insertBeforeCursor - :description: Insert a new element before the cursor position. - */ - public func insertBeforeCursor(element: Element) { - if nil === current || head === current { - insertAtFront(element) - } else { - let z: DoublyLinkedListNode = DoublyLinkedListNode(next: current, previous: current!.previous, element: element) - current!.previous?.next = z - current!.previous = z - count += 1 - } - } - - /** - :name: insertAfterCursor - :description: Insert a new element after the cursor position. - */ - public func insertAfterCursor(element: Element) { - if nil === current || tail === current { - insertAtBack(element) - } else { - let z: DoublyLinkedListNode = DoublyLinkedListNode(next: current!.next, previous: current, element: element) - current!.next?.previous = z - current!.next = z - count += 1 - } - } - - /** - :name: removeAtCursor - :description: Removes the element at the cursor position. - - returns: Element? - */ - public func removeAtCursor() -> Element? { - if 1 >= count { - return removeAtFront() - } else { - let element: Element? = current!.element - current!.previous?.next = current!.next - current!.next?.previous = current!.previous - if tail === current { - current = tail!.previous - tail = current - } else if head === current { - current = head!.next - head = current - } else { - current = current!.next - } - count -= 1 - return element - } - } - - /** - :name: reset - :description: Reinitializes pointers to sentinel value. - */ - private func reset() { - head = nil - tail = nil - current = nil - } +public struct DoublyLinkedList: CustomStringConvertible, Sequence { + public typealias Iterator = AnyIterator + + /** + First node in the list. + - Returns: An optional DoublyLinkedListNode. + */ + private var head: DoublyLinkedListNode? + + /** + Last node in list. + - Returns: An optional DoublyLinkedListNode. + */ + private var tail: DoublyLinkedListNode? + + /** + Current cursor position when iterating. + - Returns: An optional DoublyLinkedListNode. + */ + private var current: DoublyLinkedListNode? + + /** + Number of nodes in DoublyLinkedList. + - Returns: An Int. + */ + public private(set) var count: Int + + /** + Conforms to Printable Protocol. + - Returns: A String. + */ + public var description: String { + var output = "(" + var c = 0 + var x = head + while nil !== x { + output += "\(String(describing: x))" + c += 1 + if c != count { + output += ", " + } + x = x!.next + } + output += ")" + return output + } + + /** + Retrieves the data at first node of the DoublyLinkedList. + - Returns: An optional Element. + */ + public var front: Element? { + return head?.element + } + + /** + Retrieves the element at the back node of teh DoublyLinkedList. + - Returns: An optional Element. + */ + public var back: Element? { + return tail?.element + } + + /** + Retrieves the element at the current iterator position + in the DoublyLinkedList. + - Returns: An optional Element. + */ + public var cursor: Element? { + return current?.element + } + + /** + A boolean of whether the DoublyLinkedList is empty. + - Returns: A boolean indicating if the DoubleLinkedList is + empty or not, true if yes, false otherwise. + */ + public var isEmpty: Bool { + return 0 == count + } + + /** + A boolean of whether the cursor has reached the back of the + DoublyLinkedList. + - Returns: A boolean indicating if the cursor is pointing at + the back Element, true if yes, false otherwise. + */ + public var isCursorAtBack: Bool { + return nil == cursor + } + + /** + A boolean of whether the cursor has reached the front of the + DoublyLinkedList. + - Returns: A boolean indicating if the cursor is pointing at + the front Element, true if yes, false otherwise. + */ + public var isCursorAtFront: Bool { + return nil == cursor + } + + /// An initializer. + public init() { + count = 0 + reset() + } + + /** + Retrieves the element at the poistion after the + current cursor poistion. Also moves the cursor + to that node. + - Returns: An optional Element. + */ + @discardableResult + mutating public func next() -> Element? { + current = current?.next + return current?.element + } + + /** + Retrieves the element at the poistion before the + current cursor poistion. Also moves the cursor + to that node. + - Returns: An optional Element. + */ + @discardableResult + mutating public func previous() -> Element? { + current = current?.previous + return current?.element + } + + /** + Conforms to the SequenceType Protocol. Returns the next value + in the sequence of nodes. + - Returns: A DoublyLinkedList.Iterator. + */ + public func makeIterator() -> DoublyLinkedList.Iterator { + var it = head + return AnyIterator { + defer { + it = it?.next + } + return it?.element + } + } + + /// Removes all nodes from the DoublyLinkedList. + mutating public func removeAll() { + while !isEmpty { + _ = removeAtFront() + } + } + + /** + Inserts a new Element at the front of the DoublyLinkedList. + - Parameter atFront: An Element. + */ + mutating public func insert(atFront element: Element) { + var z: DoublyLinkedListNode + if 0 == count { + z = DoublyLinkedListNode(next: nil, previous: nil, element: element) + tail = z + } else { + z = DoublyLinkedListNode(next: head, previous: nil, element: element) + head!.previous = z + } + head = z + count += 1 + if 1 == count { + current = head + } else if head === current { + current = head!.next + } + } + + /** + Removes the element at the front position. + - Returns: An optional Element. + */ + @discardableResult + mutating public func removeAtFront() -> Element? { + if 0 == count { + return nil + } + let element: Element? = head!.element + count -= 1 + if 0 == count { + reset() + } else { + head = head!.next + } + return element + } + + /** + Inserts a new Element at the back of the DoublyLinkedList. + - Parameter atBack: An Element. + */ + mutating public func insert(atBack element: Element) { + var z: DoublyLinkedListNode + if 0 == count { + z = DoublyLinkedListNode(next: nil, previous: nil, element: element) + head = z + } else { + z = DoublyLinkedListNode(next: nil, previous: tail, element: element) + tail!.next = z + } + tail = z + count += 1 + if 1 == count { + current = tail + } else if tail === current { + current = tail!.previous + } + } + + /** + Removes the element at the back position. + - Returns: An optional Element. + */ + @discardableResult + mutating public func removeAtBack() -> Element? { + if 0 == count { + return nil + } + let element = tail?.element + count -= 1 + if 0 == count { + reset() + } else { + tail = tail?.previous + } + return element + } + + /// Move the cursor to the front of the DoublyLinkedList. + mutating public func cursorToFront() { + current = head + } + + /// Move the cursor to the back of the DoublyLinkedList. + mutating public func cursorToBack() { + current = tail + } + + /** + Inserts a new Element before the cursor position. + - Parameter beforeCursor element: An Element. + */ + mutating public func insert(beforeCursor element: Element) { + if nil == current || head === current { + insert(atFront: element) + } else { + let z = DoublyLinkedListNode(next: current, previous: current!.previous, element: element) + current!.previous?.next = z + current!.previous = z + count += 1 + } + } + + /** + Inserts a new Element after the cursor position. + - Parameter afterCursor element: An Element. + */ + mutating public func insert(afterCursor element: Element) { + if nil == current || tail === current { + insert(atBack: element) + } else { + let z = DoublyLinkedListNode(next: current!.next, previous: current, element: element) + current!.next?.previous = z + current!.next = z + count += 1 + } + } + + /** + Removes the element at the cursor position. + - Returns: An optional Element. + */ + @discardableResult + mutating public func removeAtCursor() -> Element? { + if 1 >= count { + return removeAtFront() + } else { + let element = current?.element + current?.previous?.next = current?.next + current?.next?.previous = current?.previous + if tail === current { + current = tail?.previous + tail = current + } else if head === current { + current = head?.next + head = current + } else { + current = current?.next + } + count -= 1 + return element + } + } + + /** + Removes all elements and resets the head, tail, and cursor + to the sentinel value. + */ + mutating private func reset() { + head = nil + tail = nil + current = nil + } } public func +(lhs: DoublyLinkedList, rhs: DoublyLinkedList) -> DoublyLinkedList { - let l: DoublyLinkedList = DoublyLinkedList() - for x in lhs { - l.insertAtBack(x!) - } - for x in rhs { - l.insertAtBack(x!) - } - return l + var l = DoublyLinkedList() + for x in lhs { + l.insert(atBack: x) + } + for x in rhs { + l.insert(atBack: x) + } + return l } -public func +=(lhs: DoublyLinkedList, rhs: DoublyLinkedList) { - for x in rhs { - lhs.insertAtBack(x!) - } -} \ No newline at end of file +public func +=(lhs: inout DoublyLinkedList, rhs: DoublyLinkedList) { + for x in rhs { + lhs.insert(atBack: x) + } +} diff --git a/Sources/DoublyLinkedListNode.swift b/Sources/DoublyLinkedListNode.swift index e0ffea9..130f9bb 100644 --- a/Sources/DoublyLinkedListNode.swift +++ b/Sources/DoublyLinkedListNode.swift @@ -1,71 +1,66 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -internal class DoublyLinkedListNode : CustomStringConvertible { - /** - :name: next - :description: Points to the successor element in the DoublyLinkedList. - - returns: DoublyLinkedListNode? - */ - internal var next: DoublyLinkedListNode? - - /** - :name: previous - :description: points to the predacessor element in the DoublyLinkedList. - - returns: DoublyLinkedListNode? - */ - internal var previous: DoublyLinkedListNode? - - /** - :name: data - :description: Satellite data. - - returns: Element? - */ - internal var element: Element? - - /** - :name: description - :description: Conforms to the Printable Protocol. - - returns: String - */ - internal var description: String { - return "\(element)" - } - - /** - :name: init - :description: Constructor. - */ - internal init(next: DoublyLinkedListNode?, previous: DoublyLinkedListNode?, element: Element?) { - self.next = next - self.previous = previous - self.element = element - } +internal class DoublyLinkedListNode: CustomStringConvertible { + /** + :name: next + :description: Points to the successor element in the DoublyLinkedList. + - returns: DoublyLinkedListNode? + */ + internal var next: DoublyLinkedListNode? + + /** + :name: previous + :description: points to the predacessor element in the DoublyLinkedList. + - returns: DoublyLinkedListNode? + */ + internal var previous: DoublyLinkedListNode? + + /** + :name: data + :description: Satellite data. + - returns: Element? + */ + internal var element: Element? + + /** + :name: description + :description: Conforms to the Printable Protocol. + - returns: String + */ + internal var description: String { + return "\(String(describing: element))" + } + + /** + :name: init + :description: Constructor. + */ + internal init(next: DoublyLinkedListNode?, previous: DoublyLinkedListNode?, element: Element?) { + self.next = next + self.previous = previous + self.element = element + } } diff --git a/Sources/Info.plist b/Sources/Info.plist index a70ac6a..d353b3e 100644 --- a/Sources/Info.plist +++ b/Sources/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.0.8 + 3.1.1 CFBundleSignature ???? CFBundleVersion diff --git a/Sources/LICENSE b/Sources/LICENSE index b4ebbfc..ae5f098 100644 --- a/Sources/LICENSE +++ b/Sources/LICENSE @@ -1,16 +1,22 @@ -Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . All rights reserved. +The MIT License (MIT) -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Copyright (C) 2019, CosmicMind, Inc. . +All rights reserved. -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -* 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. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -* Neither the name of Algorithm nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -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. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Sources/Probable.swift b/Sources/Probable.swift new file mode 100644 index 0000000..2617ba3 --- /dev/null +++ b/Sources/Probable.swift @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +internal protocol Probable { + associatedtype ProbableElement: Equatable + + /** + The instance count of elements. + - Parameter of elements: A list of ProbableElements + - Returns: An Int. + */ + func count(of elements: ProbableElement...) -> Int + + /** + The instance count of elements. + - Parameter of elements: An Array of ProbableElements. + - Returns: An Int. + */ + func count(of elements: [ProbableElement]) -> Int + + /** + The probability of given elements. + - Parameter of elements: A list of ProbableElements. + - Returns: A Double. + */ + func probability(of elements: ProbableElement...) -> Double + + /** + The probability of given elements. + - Parameter of elements: An Array of ProbableElements. + - Returns: A Double. + */ + func probability(of elements: [ProbableElement]) -> Double + + /** + The expected value of given elements based on a number of trials. + - Parameter trials: An Int. + - Parameter for elements: A list of ProbableElements. + - Returns: A Double. + */ + func expectedValue(trials: Int, for elements: ProbableElement...) -> Double + + /** + The expected value of given elements based on a number of trials. + - Parameter trials: An Int. + - Parameter for elements: An Array of ProbableElements. + - Returns: A Double. + */ + func expectedValue(trials: Int, for elements: [ProbableElement]) -> Double +} diff --git a/Sources/ProbableType.swift b/Sources/ProbableType.swift deleted file mode 100644 index e6b524d..0000000 --- a/Sources/ProbableType.swift +++ /dev/null @@ -1,81 +0,0 @@ -/* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ - -internal protocol ProbableType { - /** - :name: countOf - :description: The instance count of elements. - - parameter elements: Element... The element values to count. - - returns: Int - */ - func countOf(elements: Element...) -> Int - - /** - :name: countOf - :description: The instance count of elements. - - parameter elements: Array An array of element values to count. - - returns: Int - */ - func countOf(elements: Array) -> Int - - /** - :name: probabilityOf - :description: The probability of elements. - - parameter elements: Element... The element values to determine the probability of. - - returns: Double - */ - func probabilityOf(elements: Element...) -> Double - - /** - :name: probabilityOf - :description: The probability of elements. - - parameter elements: Array An array of element values to determine the probability of. - - returns: Double - */ - func probabilityOf(elements: Array) -> Double - - /** - :name: expectedValueOf - :description: The expected value of elements. - - parameter trials: Int The number of trials to execute. - - parameter elements: Element... The element values to determine the expected value of. - - returns: Double - */ - func expectedValueOf(trials: Int, elements: Element...) -> Double - - /** - :name: expectedValueOf - :description: The expected value of elements. - - parameter trials: Int The number of trials to execute. - - parameter elements: Array An array of element values to determine the expected value of. - - returns: Double - */ - func expectedValueOf(trials: Int, elements: Array) -> Double -} diff --git a/Sources/Queue.swift b/Sources/Queue.swift index 65bc46f..9f030f2 100644 --- a/Sources/Queue.swift +++ b/Sources/Queue.swift @@ -1,138 +1,133 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -public class Queue : CustomStringConvertible, SequenceType { - public typealias Generator = AnyGenerator - - /** - :name: list - :description: Underlying data structure. - - returns: DoublyLinkedList - */ - private var list: DoublyLinkedList - - /** - :name: count - :description: Total number of items in the Queue. - - returns: Int - */ - public var count: Int { - return list.count - } - - /** - :name: peek - :description: Get the element at the front of - the Queue, and do not remove it. - - returns: Element? - */ - public var peek: Element? { - return list.front - } - - /** - :name: isEmpty - :description: A boolean of whether the Queue is empty. - - returns: Bool - */ - public var isEmpty: Bool { - return list.isEmpty - } - - /** - :name: description - :description: Conforms to the Printable Protocol. - - returns: String - */ - public var description: String { - return "Queue" + list.internalDescription - } - - /** - :name: init - :description: Constructor. - */ - public init() { - list = DoublyLinkedList() - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes. - // :returns: Queue.Generator - // - public func generate() -> Queue.Generator { - return list.generate() - } - - /** - :name: enqueue - :description: Insert a new element at the back of the Queue. - */ - public func enqueue(element: Element) { - list.insertAtBack(element) - } - - /** - :name: dequeue - :description: Get and remove the element at the front - of the Queue. - - returns: Element? - */ - public func dequeue() -> Element? { - return list.removeAtFront() - } - - /** - :name: removeAll - :description: Remove all elements from the Queue. - */ - public func removeAll() { - list.removeAll() - } +public struct Queue: CustomStringConvertible, Sequence { + public typealias Iterator = AnyIterator + + /** + :name: list + :description: Underlying data structure. + - returns: DoublyLinkedList + */ + private var list: DoublyLinkedList + + /** + :name: count + :description: Total number of items in the Queue. + - returns: Int + */ + public var count: Int { + return list.count + } + + /** + :name: peek + :description: Get the element at the front of + the Queue, and do not remove it. + - returns: Element? + */ + public var peek: Element? { + return list.front + } + + /** + :name: isEmpty + :description: A boolean of whether the Queue is empty. + - returns: Bool + */ + public var isEmpty: Bool { + return list.isEmpty + } + + /** + :name: description + :description: Conforms to the Printable Protocol. + - returns: String + */ + public var description: String { + return list.description + } + + /** + :name: init + :description: Constructor. + */ + public init() { + list = DoublyLinkedList() + } + + // + // :name: generate + // :description: Conforms to the SequenceType Protocol. Returns + // the next value in the sequence of nodes. + // :returns: Queue.Generator + // + public func makeIterator() -> Iterator { + return list.makeIterator() + } + + /** + :name: enqueue + :description: Insert a new element at the back of the Queue. + */ + mutating public func enqueue(_ element: Element) { + list.insert(atBack: element) + } + + /** + :name: dequeue + :description: Get and remove the element at the front + of the Queue. + - returns: Element? + */ + mutating public func dequeue() -> Element? { + return list.removeAtFront() + } + + /** + :name: removeAll + :description: Remove all elements from the Queue. + */ + mutating public func removeAll() { + list.removeAll() + } + + public static func +(lhs: Queue, rhs: Queue) -> Queue { + var q = Queue() + for x in lhs { + q.enqueue(x) + } + for x in rhs { + q.enqueue(x) + } + return q + } + + public static func +=(lhs: inout Queue, rhs: Queue) { + for x in rhs { + lhs.enqueue(x) + } + } } - -public func +(lhs: Queue, rhs: Queue) -> Queue { - let q: Queue = Queue() - for x in lhs { - q.enqueue(x!) - } - for x in rhs { - q.enqueue(x!) - } - return q -} - -public func +=(lhs: Queue, rhs: Queue) { - for x in rhs { - lhs.enqueue(x!) - } -} \ No newline at end of file diff --git a/Sources/RedBlackNode.swift b/Sources/RedBlackNode.swift index 3ee8f50..f4e6746 100644 --- a/Sources/RedBlackNode.swift +++ b/Sources/RedBlackNode.swift @@ -1,134 +1,119 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -internal class RedBlackNode : Comparable, Equatable, CustomStringConvertible { - /** - :name: parent - :description: A reference to the parent node of a given node. - - returns: RedBlackNode! - */ - internal var parent: RedBlackNode! - - /** - :name: left - :description: A reference to the left child node of a given node. - - returns: RedBlackNode! - */ - internal var left: RedBlackNode! - - /** - :name: right - :description: A reference to the right child node of a given node. - - returns: RedBlackNode! - */ - internal var right: RedBlackNode! - - /** - :name: isRed - :description: A boolean indicating whether te node is marked isRed or black. - - returns: Bool - */ - internal var isRed: Bool - - /** - :name: order - :description: Used to track the order statistic of a node, which maintains - key order in the tree. - - returns: Int - */ - internal var order: Int - - /** - :name: key - :description: A reference to the key value of the node, which is what organizes - a node in a given tree. - - returns: Key! - */ - internal var key: Key! - - /** - :name: value - :description: Satellite data stoisRed in the node. - - returns: Value? - */ - internal var value: Value? - - /** - :name: description - :description: Conforms to the Printable Protocol. - - returns: String - */ - internal var description: String { - return "(\(key), \(value))" - } - - /** - :name: init - :description: Constructor used for sentinel nodes. - */ - internal init() { - isRed = false - order = 0 - } - - /** - :name: init - :description: Constructor used for nodes that store data. - */ - internal init(parent: RedBlackNode, sentinel: RedBlackNode, key: Key, value: Value?) { - self.key = key - self.value = value - self.parent = parent - left = sentinel - right = sentinel - isRed = true - order = 1 - } +internal class RedBlackNode: Comparable, Equatable, CustomStringConvertible { + /** + :name: parent + :description: A reference to the parent node of a given node. + - returns: RedBlackNode! + */ + internal var parent: RedBlackNode! + + /** + :name: left + :description: A reference to the left child node of a given node. + - returns: RedBlackNode! + */ + internal var left: RedBlackNode! + + /** + :name: right + :description: A reference to the right child node of a given node. + - returns: RedBlackNode! + */ + internal var right: RedBlackNode! + + /** + :name: isRed + :description: A boolean indicating whether te node is marked isRed or black. + - returns: Bool + */ + internal var isRed: Bool + + /** + :name: order + :description: Used to track the order statistic of a node, which maintains + key order in the tree. + - returns: Int + */ + internal var order: Int + + /** + :name: key + :description: A reference to the key value of the node, which is what organizes + a node in a given tree. + - returns: Key! + */ + internal var key: Key! + + /** + :name: value + :description: Satellite data stoisRed in the node. + - returns: Value? + */ + internal var value: Value? + + /** + :name: description + :description: Conforms to the Printable Protocol. + - returns: String + */ + internal var description: String { + return "(\(String(describing: key)), \(String(describing: value)))" + } + + /** + :name: init + :description: Constructor used for sentinel nodes. + */ + internal init() { + isRed = false + order = 0 + } + + /** + :name: init + :description: Constructor used for nodes that store data. + */ + internal init(parent: RedBlackNode, sentinel: RedBlackNode, key: Key, value: Value?) { + self.key = key + self.value = value + self.parent = parent + left = sentinel + right = sentinel + isRed = true + order = 1 + } + + static func ==(lhs: RedBlackNode, rhs: RedBlackNode) -> Bool { + return lhs.key == rhs.key + } + + static func <(lhs: RedBlackNode, rhs: RedBlackNode) -> Bool { + return lhs.key < rhs.key + } } -func ==(lhs: RedBlackNode, rhs: RedBlackNode) -> Bool { - return lhs.key == rhs.key -} - -func <=(lhs: RedBlackNode, rhs: RedBlackNode) -> Bool { - return lhs.key <= rhs.key -} - -func >=(lhs: RedBlackNode, rhs: RedBlackNode) -> Bool { - return lhs.key >= rhs.key -} - -func >(lhs: RedBlackNode, rhs: RedBlackNode) -> Bool { - return lhs.key > rhs.key -} -func <(lhs: RedBlackNode, rhs: RedBlackNode) -> Bool { - return lhs.key < rhs.key -} diff --git a/Sources/RedBlackTree.swift b/Sources/RedBlackTree.swift index a167424..61401d7 100644 --- a/Sources/RedBlackTree.swift +++ b/Sources/RedBlackTree.swift @@ -1,813 +1,899 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ - -public class RedBlackTree : ProbableType, CollectionType, CustomStringConvertible { - public typealias Generator = AnyGenerator<(key: Key, value: Value?)> - - /** - Total number of elements within the RedBlackTree - */ - public internal(set) var count: Int = 0 - - /** - :name: sentinel - :description: A node used to mark the end of a path in the tree. - - returns: RedBlackNode - */ - internal private(set) var sentinel: RedBlackNode - - /** - :name: root - :description: The root of the tree data structure. - - returns: RedBlackNode - */ - internal private(set) var root: RedBlackNode - - /** - :name: internalDescription - :description: Returns a String with only the node data for all - nodes in the Tree. - - returns: String - */ - internal var internalDescription: String { - var output: String = "[" - let l: Int = count - 1 - for i in 0..() - root = sentinel - } - - /** - :name: init - :description: Constructor where the tree is optionally allowed - to store uniqe or non-unique keys. - - parameter uniqueKeys: Bool Set the keys to be unique. - */ - public init(uniqueKeys: Bool) { - isUniquelyKeyed = uniqueKeys - sentinel = RedBlackNode() - root = sentinel - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes using - // index values [0...n-1]. - // :returns: RedBlackTree.Generator - // - public func generate() -> RedBlackTree.Generator { - var index = startIndex - return AnyGenerator { - if index < self.endIndex { - let i: Int = index - index += 1 - return self[i] - } - return nil - } - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: T...) -> Int { - return countOf(keys) - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: Array) -> Int { - var c: Int = 0 - for key in keys { - internalCount(key as! Key, node: root, count: &c) - } - return c - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: T...) -> Double { - return probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Array) -> Double { - return 0 == count ? 0 : Double(countOf(elements)) / Double(count) - } - - /** - The probability of elements. - */ - public func probabilityOf(block: (key: Key, value: Value?) -> Bool) -> Double { - if 0 == count { - return 0 - } - - var c: Int = 0 - for (k, v) in self { - if block(key: k, value: v) { - c += 1 - } - } - return Double(c) / Double(count) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: T...) -> Double { - return expectedValueOf(trials, elements: elements) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Array) -> Double { - return Double(trials) * probabilityOf(elements) - } - - /** - :name: insert - :description: Insert a key / value pair. - - returns: Bool - */ - public func insert(key: Key, value: Value?) -> Bool { - return sentinel !== internalInsert(key, value: value) - } - - /** - :name: insert - :description: Inserts a list of (Key, Value?) pairs. - - parameter nodes: (Key, Value?)... Elements to insert. - */ - public func insert(nodes: (Key, Value?)...) { - insert(nodes) - } - - /** - :name: insert - :description: Inserts an array of (Key, Value?) pairs. - - parameter nodes: Array<(Key, Value?)> Elements to insert. - */ - public func insert(nodes: Array<(Key, Value?)>) { - for (k, v) in nodes { - insert(k, value: v) - } - } - - /** - :name: removeValueForKeys - :description: Removes a node from the tree based on the key value given. - If the tree allows non-unique keys, then all keys matching - the given key value will be removed. - - returns: RedBlackTree? - */ - public func removeValueForKeys(keys: Key...) { - return removeValueForKeys(keys) - } - - /** - :name: removeValueForKeys - :description: Removes a key / value pairs from the tree based on the key given. - If the tree allows non-unique keys, then all keys matching - the given key will be removed. - - returns: RedBlackTree? - */ - public func removeValueForKeys(keys: Array) { - for x in keys { - var z: RedBlackNode = internalRemoveValueForKey(x) - while sentinel !== z { - z = internalRemoveValueForKey(x) - } - } - } - - /** - :name: removeValueForKey - :description: Removes a single instance of a value for a key. This is - important when using non-unique keys. - - returns: Value? - */ - public func removeInstanceValueForKey(key: Key) -> Value? { - return internalRemoveValueForKey(key).value - } - - /** - :name: removeAll - :description: Remove all nodes from the tree. - */ - public func removeAll() { - while sentinel !== root { - internalRemoveValueForKey(root.key) - } - } - - /** - :name: updateValue - :description: Updates a node for the given key value. - If the tree allows non-unique keys, then all keys matching - the given key value will be updated. - */ - public func updateValue(value: Value?, forKey: Key) { - internalUpdateValue(value, forKey: forKey, node: root) - } - - /** - :name: findValueForKey - :description: Finds the first instance in a non-unique tree and only instance - in isUniquelyKeyed tree of a given keyed node. - - returns: Value? - */ - public func findValueForKey(key: Key) -> Value? { - return internalFindNodeForKey(key).value - } - - /** - :name: operator [0...count - 1] - :description: Allows array like access of the index. - Items are kept in order, so when iterating - through the items, they are returned in their - ordeisRed form. - - returns: (key: Key, value: Value?) - */ - public subscript(index: Int) -> (key: Key, value: Value?) { - get { - let x: RedBlackNode = internalSelect(root, order: index + 1) - return (x.key, x.value) - } - set(element) { - internalUpdateValue(element.value, forKey: element.key, node: root) - } - } - - /** - :name: operator ["key1"..."keyN"] - :description: Property key mapping. If the key type is a - String, this feature allows access like a - Dictionary. - - returns: Value? - */ - public subscript(key: Key) -> Value? { - get { - return internalFindNodeForKey(key).value - } - set(value) { - if sentinel === internalFindNodeForKey(key) { - internalInsert(key, value: value) - } else { - updateValue(value, forKey: key) - } - } - } - - /** - :name: indexOf - :description: Returns the Index of a given member, or nil if the member is not present in the set. - - returns: Int - */ - public func indexOf(key: Key) -> Int { - let x: RedBlackNode = internalFindNodeForKey(key) - return sentinel === x ? -1 : internalOrder(x) - 1 - } - - /** - :name: internalInsert - :description: Insert a new node with the given key and value. - - returns: RedBlackNode - */ - private func internalInsert(key: Key, value: Value?) -> RedBlackNode { - if isUniquelyKeyed && sentinel !== internalFindNodeForKey(key) { - return sentinel; - } - - var y: RedBlackNode = sentinel - var x: RedBlackNode = root - - while x !== sentinel { - y = x - y.order += 1 - x = key < x.key ? x.left : x.right - } - - let z: RedBlackNode = RedBlackNode(parent: y, sentinel: sentinel, key: key, value: value) - - if y === sentinel { - root = z - } else if key < y.key { - y.left = z - } else { - y.right = z - } - - insertCleanUp(z) - count += 1 - return z - } - - /** - :name: insertCleanUp - :description: The clean up procedure needed to maintain the RedBlackTree balance. - - returns: RedBlackNode - */ - private func insertCleanUp(node: RedBlackNode) { - var z: RedBlackNode = node - while z.parent.isRed { - if z.parent === z.parent.parent.left { - let y: RedBlackNode = z.parent.parent.right - // violation 1, parent child relationship re to isRed - if y.isRed { - z.parent.isRed = false - y.isRed = false - z.parent.parent.isRed = true - z = z.parent.parent - } else { - // case 2, parent is isRed, uncle is black - if z === z.parent.right { - z = z.parent - leftRotate(z) - } - // case 3, balance colours - z.parent.isRed = false - z.parent.parent.isRed = true - rightRotate(z.parent.parent) - } - } else { - // symetric - let y: RedBlackNode = z.parent.parent.left - // violation 1, parent child relationship re to isRed - if y.isRed { - z.parent.isRed = false - y.isRed = false - z.parent.parent.isRed = true - z = z.parent.parent - } else { - // case 2, parent is isRed, uncle is black - if z === z.parent.left { - z = z.parent - rightRotate(z) - } - // case 3, balance colours - z.parent.isRed = false - z.parent.parent.isRed = true - leftRotate(z.parent.parent) - } - } - } - root.isRed = false - } - - /** - :name: internalRemoveValueForKey - :description: Removes a node with the given key value and returns that - node. If the value does not exist, the sentinel is returned. - - returns: RedBlackNode - */ - private func internalRemoveValueForKey(key: Key) -> RedBlackNode { - let z: RedBlackNode = internalFindNodeForKey(key) - if z === sentinel { - return sentinel - } - - if z !== root { - var t: RedBlackNode = z.parent - while t !== root { - t.order -= 1 - t = t.parent - } - root.order -= 1 - } - - - var x: RedBlackNode! - var y: RedBlackNode = z - var isRed: Bool = y.isRed - - if z.left === sentinel { - x = z.right - transplant(z, v: z.right) - } else if z.right === sentinel { - x = z.left - transplant(z, v: z.left) - } else { - y = minimum(z.right) - isRed = y.isRed - x = y.right - if y.parent === z { - x.parent = y - } else { - transplant(y, v: y.right) - y.right = z.right - y.right.parent = y - var t: RedBlackNode = x.parent - while t !== y { - t.order -= 1 - t = t.parent - } - y.order = y.left.order + 1 - } - transplant(z, v: y) - y.left = z.left - y.left.parent = y - y.isRed = z.isRed - y.order = y.left.order + y.right.order + 1 - } - if !isRed { - removeCleanUp(x) - } - count -= 1 - return z - } - - /** - :name: removeCleanUp - :description: After a successful removal of a node, the RedBlackTree - is rebalanced by this method. - */ - private func removeCleanUp(node: RedBlackNode) { - var x: RedBlackNode = node - while x !== root && !x.isRed { - if x === x.parent.left { - var y: RedBlackNode = x.parent.right - if y.isRed { - y.isRed = false - x.parent.isRed = true - leftRotate(x.parent) - y = x.parent.right - } - if !y.left.isRed && !y.right.isRed { - y.isRed = true - x = x.parent - } else { - if !y.right.isRed { - y.left.isRed = false - y.isRed = true - rightRotate(y) - y = x.parent.right - } - y.isRed = x.parent.isRed - x.parent.isRed = false - y.right.isRed = false - leftRotate(x.parent) - x = root - } - } else { // symetric left and right - var y: RedBlackNode = x.parent.left - if y.isRed { - y.isRed = false - x.parent.isRed = true - rightRotate(x.parent) - y = x.parent.left - } - if !y.right.isRed && !y.left.isRed { - y.isRed = true - x = x.parent - } else { - if !y.left.isRed { - y.right.isRed = false - y.isRed = true - leftRotate(y) - y = x.parent.left - } - y.isRed = x.parent.isRed - x.parent.isRed = false - y.left.isRed = false - rightRotate(x.parent) - x = root - } - } - } - x.isRed = false - } - - /** - :name: minimum - :description: Finds the minimum keyed node. - - returns: RedBlackNode - */ - private func minimum(node: RedBlackNode) -> RedBlackNode { - var x: RedBlackNode = node - var y: RedBlackNode = sentinel - while x !== sentinel { - y = x - x = x.left - } - return y - } - - /** - :name: transplant - :description: Swaps two subTrees in the tree. - */ - private func transplant(u: RedBlackNode, v: RedBlackNode) { - if u.parent === sentinel { - root = v - } else if u === u.parent.left { - u.parent.left = v - } else { - u.parent.right = v - } - v.parent = u.parent - } - - /** - :name: leftRotate - :description: Rotates the nodes to satisfy the RedBlackTree - balance property. - */ - private func leftRotate(x: RedBlackNode) { - let y: RedBlackNode = x.right - - x.right = y.left - if sentinel !== y.left { - y.left.parent = x - } - - y.parent = x.parent - - if sentinel === x.parent { - root = y - } else if x === x.parent.left { - x.parent.left = y - } else { - x.parent.right = y - } - - y.left = x - x.parent = y - y.order = x.order - x.order = x.left.order + x.right.order + 1 - } - - /** - :name: rightRotate - :description: Rotates the nodes to satisfy the RedBlackTree - balance property. - */ - private func rightRotate(y: RedBlackNode) { - let x: RedBlackNode = y.left - - y.left = x.right - if sentinel !== x.right { - x.right.parent = y - } - - x.parent = y.parent - - if sentinel === y.parent { - root = x - } else if y === y.parent.right { - y.parent.right = x - } else { - y.parent.left = x - } - - x.right = y - y.parent = x - x.order = y.order - y.order = y.left.order + y.right.order + 1 - } - - /** - :name: internalFindNodeForKey - :description: Finds a node with a given key value. - - returns: RedBlackNode - */ - private func internalFindNodeForKey(key: Key) -> RedBlackNode { - var z: RedBlackNode = root - while z !== sentinel { - if key == z.key { - return z - } - z = key < z.key ? z.left : z.right - } - return sentinel - } - - /** - :name: internalSelect - :description: Internally searches for a node by the order statistic value. - - returns: RedBlackNode - */ - private func internalSelect(x: RedBlackNode, order: Int) -> RedBlackNode { - validateOrder(order) - let r: Int = x.left.order + 1 - if order == r { - return x - } else if order < r { - return internalSelect(x.left, order: order) - } - return internalSelect(x.right, order: order - r) - } - - /** - :name: internalCount - :description: Traverses the Tree while counting number of times a key appears. - */ - private func internalCount(key: Key, node: RedBlackNode, inout count: Int) { - if sentinel !== node { - if key == node.key { - count += 1 - } - internalCount(key, node: node.left, count: &count) - internalCount(key, node: node.right, count: &count) - } - } - - /** - :name: internalUpdateValue - :description: Traverses the Tree and updates all the values that match the key. - */ - private func internalUpdateValue(value: Value?, forKey: Key, node: RedBlackNode) { - if node !== sentinel { - if forKey == node.key { - node.value = value - } - internalUpdateValue(value, forKey: forKey, node: node.left) - internalUpdateValue(value, forKey: forKey, node: node.right) - } - } - - /** - :name: internalOrder - :description: Traverses the Tree for the internal order statistic of a key. - - returns: Int - */ - private func internalOrder(node: RedBlackNode) -> Int { - var x: RedBlackNode = node - var r: Int = x.left.order + 1 - while root !== x { - if x.parent.right === x { - r += x.parent.left.order + 1 - } - x = x.parent - } - return r - } - - /** - :name: validateOrder - :description: Validates the order statistic being within range of 1...n. - */ - private func validateOrder(order: Int) { - assert(order >= startIndex || order < endIndex, "[Algorithm Error: Order out of bounds.]") - } -} - -public func ==(lhs: RedBlackTree, rhs: RedBlackTree) -> Bool { - if lhs.count != rhs.count { - return false - } - for i in 0..(lhs: RedBlackTree, rhs: RedBlackTree) -> Bool { - return !(lhs == rhs) -} - -public func +(lhs: RedBlackTree, rhs: RedBlackTree) -> RedBlackTree { - let t: RedBlackTree = lhs - for (k, v) in rhs { - t.insert(k, value: v) - } - return t + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +public struct RedBlackTree: Probable, Collection, BidirectionalCollection, CustomStringConvertible { + public typealias Element = (key: Key, value: Value?) + public typealias ProbableElement = Key + + /// Returns the position immediately after the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be less than + /// `endIndex`. + /// - Returns: The index value immediately after `i`. + public func index(after i: Int) -> Int { + return i + 1 + } + + public func index(before i: Int) -> Int { + return i - 1 + } + + public typealias Iterator = AnyIterator + + /** + Total number of elements within the RedBlackTree + */ + public internal(set) var count = 0 + + /** + :name: sentinel + :description: A node used to mark the end of a path in the tree. + - returns: RedBlackNode + */ + internal private(set) var sentinel: RedBlackNode + + /** + :name: root + :description: The root of the tree data structure. + - returns: RedBlackNode + */ + internal private(set) var root: RedBlackNode + + /** + :name: isUniquelyKeyed + :description: A boolean used to indicate whether to allow the + tree to store non-unique key values or only unique + key values. + - returns: Bool + */ + public private(set) var isUniquelyKeyed: Bool + + /** + :name: description + :description: Conforms to the Printable Protocol. Outputs the + data in the Tree in a readable format. + - returns: String + */ + public var description: String { + return "[" + map { "\($0)" }.joined(separator: ", ") + "]" + } + + /** + :name: startIndex + :description: Conforms to the Collection Protocol. + - returns: Int + */ + public var startIndex: Int { + return 0 + } + + /** + :name: endIndex + :description: Conforms to the Collection Protocol. + - returns: Int + */ + public var endIndex: Int { + return count + } + + /** + :name: first + :description: Get the first node value in the tree, this is + the first node based on the order of keys where + k1 <= k2 <= K3 ... <= Kn + - returns: Element? + */ + public var first: Element? { + guard 0 < count else { + return nil + } + + return self[0] + } + + /** + :name: last + :description: Get the last node value in the tree, this is + the last node based on the order of keys where + k1 <= k2 <= K3 ... <= Kn + - returns: Element? + */ + public var last: Element? { + guard 0 < count else { + return nil + } + + return self[count - 1] + } + + /// Retrieves an Array of the key values in order. + public var keys: [Key] { + return map { $0.key } + } + + /// Retrieves an Array of the values that are sorted based. + public var values: [Value] { + return compactMap { $0.value } + } + + /** + :name: init + :description: Constructor where the tree is guaranteed to store + non-unique keys. + */ + public init() { + isUniquelyKeyed = false + sentinel = RedBlackNode() + root = sentinel + } + + /** + :name: init + :description: Constructor where the tree is optionally allowed + to store uniqe or non-unique keys. + - parameter uniqueKeys: Bool Set the keys to be unique. + */ + public init(uniqueKeys: Bool) { + isUniquelyKeyed = uniqueKeys + sentinel = RedBlackNode() + root = sentinel + } + + public func _customIndexOfEquatableElement(_ element: Key) -> Int?? { + return nil + } + + // + // :name: generate + // :description: Conforms to the SequenceType Protocol. Returns + // the next value in the sequence of nodes using + // index values [0...n-1]. + // :returns: RedBlackTree.Generator + // + public func makeIterator() -> RedBlackTree.Iterator { + var i = indices.makeIterator() + return AnyIterator { i.next().map { self[$0] } } + } + + /** + Conforms to Probable protocol. + */ + public func count(of keys: Key...) -> Int { + return count(of: keys) + } + + /** + Conforms to Probable protocol. + */ + public func count(of keys: [Key]) -> Int { + var c = 0 + + for k in keys { + internalCount(k, node: root, count: &c) + } + + return c + } + + /** + The probability of elements. + */ + public func probability(of keys: Key...) -> Double { + return probability(of: keys) + } + + /** + The probability of elements. + */ + public func probability(of keys: [Key]) -> Double { + return 0 == count ? 0 : Double(count(of: keys)) / Double(count) + } + + /** + The probability of elements. + */ + public func probability(execute block: (Key, Value?) -> Bool) -> Double { + if 0 == count { + return 0 + } + + var c = 0 + + for (k, v) in self { + if block(k, v) { + c += 1 + } + } + + return Double(c) / Double(count) + } + + /** + The expected value of elements. + */ + public func expectedValue(trials: Int, for keys: Key...) -> Double { + return expectedValue(trials: trials, for: keys) + } + + /** + The expected value of elements. + */ + public func expectedValue(trials: Int, for keys: [Key]) -> Double { + return Double(trials) * probability(of: keys) + } + + /** + :name: insert + :description: Insert a key / value pair. + - returns: Bool + */ + @discardableResult + mutating public func insert(value: Value?, for key: Key) -> Bool { + return sentinel !== internalInsert(key, value: value) + } + + /** + :name: insert + :description: Inserts a list of (Key, Value?) pairs. + - parameter nodes: (Key, Value?)... Elements to insert. + */ + mutating public func insert(_ nodes: (Key, Value?)...) { + insert(nodes) + } + + /** + :name: insert + :description: Inserts an array of (Key, Value?) pairs. + - parameter nodes: [(Key, Value?)] Elements to insert. + */ + mutating public func insert(_ nodes: [(Key, Value?)]) { + for (k, v) in nodes { + insert(value: v, for: k) + } + } + + /** + :name: removeValueForKeys + :description: Removes a node from the tree based on the key value given. + If the tree allows non-unique keys, then all keys matching + the given key value will be removed. + - returns: RedBlackTree? + */ + mutating public func removeValue(for keys: Key...) { + return removeValue(for: keys) + } + + /** + :name: removeValueForKeys + :description: Removes a key / value pairs from the tree based on the key given. + If the tree allows non-unique keys, then all keys matching + the given key will be removed. + - returns: RedBlackTree? + */ + mutating public func removeValue(for keys: [Key]) { + for x in keys { + var z = internalRemoveValueForKey(x) + + while sentinel !== z { + z = internalRemoveValueForKey(x) + } + } + } + + /** + :name: removeValueForKey + :description: Removes a single instance of a value for a key. This is + important when using non-unique keys. + - returns: Value? + */ + @discardableResult + mutating public func removeInstanceValueForKey(_ key: Key) -> Value? { + return internalRemoveValueForKey(key).value + } + + /** + :name: removeAll + :description: Remove all nodes from the tree. + */ + mutating public func removeAll() { + while sentinel !== root { + internalRemoveValueForKey(root.key) + } + } + + /** + :name: updateValue + :description: Updates a node for the given key value. + If the tree allows non-unique keys, then all keys matching + the given key value will be updated. + */ + mutating public func update(value: Value?, for key: Key) { + internalUpdateValue(value, for: key, node: root) + } + + /** + :name: findValueForKey + :description: Finds the first instance in a non-unique tree and only instance + in isUniquelyKeyed tree of a given keyed node. + - returns: Value? + */ + public func findValue(for key: Key) -> Value? { + return internalFindNodeForKey(key).value + } + + /** + :name: findLowerValue + :description: Finds instance with key that is lower or equal input key + - returns: Value? + */ + public func findLowerValue(for key: Key) -> Value? { + return internalFindLowerForKey(key).value + } + + /** + :name: findCeilingValue + :description: Finds instance with key that is larger or equal input key + - returns: Value? + */ + public func findCeilingValue(for key: Key) -> Value? { + return internalFindCeilingForKey(key).value + } + + /** + Returns the Key value at a given position. + - Parameter position: An Int. + - Returns: A Key. + */ + public subscript(position: Int) -> Key { + return self[position].key + } + + /** + :name: operator [0...count - 1] + :description: Allows array like access of the index. + Items are kept in order, so when iterating + through the items, they are returned in their + ordeisRed form. + - returns: (key: Key, value: Value?) + */ + public subscript(index: Int) -> (key: Key, value: Value?) { + get { + let x = internalSelect(root, order: index + 1) + return (x.key, x.value) + } + set(element) { + internalUpdateValue(element.value, for: element.key, node: root) + } + } + + /** + :name: operator ["key1"..."keyN"] + :description: Property key mapping. If the key type is a + String, this feature allows access like a + Dictionary. + - returns: Value? + */ + public subscript(key: Key) -> Value? { + get { + return internalFindNodeForKey(key).value + } + set(value) { + if sentinel === internalFindNodeForKey(key) { + _ = internalInsert(key, value: value) + } else { + update(value: value, for: key) + } + } + } + + /** + :name: internalFindLowerForKey + :description: Finds a node with a key that is equal or less that given. + - returns: RedBlackNode + */ + private func internalFindLowerForKey(_ key: Key) -> RedBlackNode { + var z = root + var max = sentinel + + while z !== sentinel { + if key > z.key { + max = z + } + if key == z.key { + return z + } + z = key < z.key as Key ? z.left : z.right + } + return max + } + + /** + :name: internalFindCeilingForKey + :description: Finds a node with a key that is equal or larger that given. + - returns: RedBlackNode + */ + private func internalFindCeilingForKey(_ key: Key) -> RedBlackNode { + var z = root + var min = sentinel + + while z !== sentinel { + if key < z.key { + min = z + } + if key == z.key { + return z + } + z = key < z.key as Key ? z.left : z.right + } + return min + } + + /** + :name: indexOf + :description: Returns the Index of a given member, or nil if the member is not present in the set. + - returns: Int + */ + public func index(of key: Key) -> Int { + let x = internalFindNodeForKey(key) + return sentinel === x ? -1 : internalOrder(x) - 1 + } + + /** + :name: internalInsert + :description: Insert a new node with the given key and value. + - returns: RedBlackNode + */ + mutating private func internalInsert(_ key: Key, value: Value?) -> RedBlackNode { + if isUniquelyKeyed && sentinel !== internalFindNodeForKey(key) { + return sentinel; + } + + var y = sentinel + var x = root + + while x !== sentinel { + y = x + y.order += 1 + x = key < x.key as Key ? x.left : x.right + } + + let z = RedBlackNode(parent: y, sentinel: sentinel, key: key, value: value) + + if y === sentinel { + root = z + } else if key < y.key as Key { + y.left = z + } else { + y.right = z + } + + insertCleanUp(z) + count += 1 + return z + } + + /** + :name: insertCleanUp + :description: The clean up procedure needed to maintain the RedBlackTree balance. + - returns: RedBlackNode + */ + mutating private func insertCleanUp(_ node: RedBlackNode) { + var z = node + while z.parent.isRed { + if z.parent === z.parent.parent.left { + let y = z.parent.parent.right! + // violation 1, parent child relationship re to isRed + if y.isRed { + z.parent.isRed = false + y.isRed = false + z.parent.parent.isRed = true + z = z.parent.parent + } else { + // case 2, parent is isRed, uncle is black + if z === z.parent.right { + z = z.parent + leftRotate(z) + } + // case 3, balance colours + z.parent.isRed = false + z.parent.parent.isRed = true + rightRotate(z.parent.parent) + } + } else { + // symetric + let y = z.parent.parent.left! + // violation 1, parent child relationship re to isRed + if y.isRed { + z.parent.isRed = false + y.isRed = false + z.parent.parent.isRed = true + z = z.parent.parent + } else { + // case 2, parent is isRed, uncle is black + if z === z.parent.left { + z = z.parent + rightRotate(z) + } + // case 3, balance colours + z.parent.isRed = false + z.parent.parent.isRed = true + leftRotate(z.parent.parent) + } + } + } + root.isRed = false + } + + /** + :name: internalRemoveValueForKey + :description: Removes a node with the given key value and returns that + node. If the value does not exist, the sentinel is returned. + - returns: RedBlackNode + */ + @discardableResult + mutating private func internalRemoveValueForKey(_ key: Key) -> RedBlackNode { + let z = internalFindNodeForKey(key) + if z === sentinel { + return sentinel + } + + if z !== root { + var t = z.parent! + while t !== root { + t.order -= 1 + t = t.parent + } + root.order -= 1 + } + + var x: RedBlackNode! + var y = z + var isRed = y.isRed + + if z.left === sentinel { + x = z.right + transplant(z, v: z.right) + } else if z.right === sentinel { + x = z.left + transplant(z, v: z.left) + } else { + y = minimum(z.right) + isRed = y.isRed + x = y.right + if y.parent === z { + x.parent = y + } else { + transplant(y, v: y.right) + y.right = z.right + y.right.parent = y + var t = x.parent! + while t !== y { + t.order -= 1 + t = t.parent + } + y.order = y.left.order + 1 + } + transplant(z, v: y) + y.left = z.left + y.left.parent = y + y.isRed = z.isRed + y.order = y.left.order + y.right.order + 1 + } + if !isRed { + removeCleanUp(x) + } + count -= 1 + return z + } + + /** + :name: removeCleanUp + :description: After a successful removal of a node, the RedBlackTree + is rebalanced by this method. + */ + mutating private func removeCleanUp(_ node: RedBlackNode) { + var x = node + while x !== root && !x.isRed { + if x === x.parent.left { + var y = x.parent.right! + if y.isRed { + y.isRed = false + x.parent.isRed = true + leftRotate(x.parent) + y = x.parent.right + } + if !y.left.isRed && !y.right.isRed { + y.isRed = true + x = x.parent + } else { + if !y.right.isRed { + y.left.isRed = false + y.isRed = true + rightRotate(y) + y = x.parent.right + } + y.isRed = x.parent.isRed + x.parent.isRed = false + y.right.isRed = false + leftRotate(x.parent) + x = root + } + } else { // symetric left and right + var y = x.parent.left! + if y.isRed { + y.isRed = false + x.parent.isRed = true + rightRotate(x.parent) + y = x.parent.left + } + if !y.right.isRed && !y.left.isRed { + y.isRed = true + x = x.parent + } else { + if !y.left.isRed { + y.right.isRed = false + y.isRed = true + leftRotate(y) + y = x.parent.left + } + y.isRed = x.parent.isRed + x.parent.isRed = false + y.left.isRed = false + rightRotate(x.parent) + x = root + } + } + } + x.isRed = false + } + + /** + :name: minimum + :description: Finds the minimum keyed node. + - returns: RedBlackNode + */ + private func minimum(_ node: RedBlackNode) -> RedBlackNode { + var x = node + var y = sentinel + while x !== sentinel { + y = x + x = x.left + } + return y + } + + /** + :name: transplant + :description: Swaps two subTrees in the tree. + */ + mutating private func transplant(_ u: RedBlackNode, v: RedBlackNode) { + if u.parent === sentinel { + root = v + } else if u === u.parent.left { + u.parent.left = v + } else { + u.parent.right = v + } + v.parent = u.parent + } + + /** + :name: leftRotate + :description: Rotates the nodes to satisfy the RedBlackTree + balance property. + */ + mutating private func leftRotate(_ x: RedBlackNode) { + let y = x.right! + + x.right = y.left + if sentinel !== y.left { + y.left.parent = x + } + + y.parent = x.parent + + if sentinel === x.parent { + root = y + } else if x === x.parent.left { + x.parent.left = y + } else { + x.parent.right = y + } + + y.left = x + x.parent = y + y.order = x.order + x.order = x.left.order + x.right.order + 1 + } + + /** + :name: rightRotate + :description: Rotates the nodes to satisfy the RedBlackTree + balance property. + */ + mutating private func rightRotate(_ y: RedBlackNode) { + let x = y.left! + + y.left = x.right + if sentinel !== x.right { + x.right.parent = y + } + + x.parent = y.parent + + if sentinel === y.parent { + root = x + } else if y === y.parent.right { + y.parent.right = x + } else { + y.parent.left = x + } + + x.right = y + y.parent = x + x.order = y.order + y.order = y.left.order + y.right.order + 1 + } + + /** + :name: internalFindNodeForKey + :description: Finds a node with a given key value. + - returns: RedBlackNode + */ + private func internalFindNodeForKey(_ key: Key) -> RedBlackNode { + var z = root + while z !== sentinel { + if key == z.key { + return z + } + z = key < z.key as Key ? z.left : z.right + } + return sentinel + } + + /** + :name: internalSelect + :description: Internally searches for a node by the order statistic value. + - returns: RedBlackNode + */ + private func internalSelect(_ x: RedBlackNode, order: Int) -> RedBlackNode { + validateOrder(order) + + let r = x.left.order + 1 + + if order == r { + return x + } else if order < r { + return internalSelect(x.left, order: order) + } + + return internalSelect(x.right, order: order - r) + } + + /** + :name: internalCount + :description: Traverses the Tree while counting number of times a key appears. + */ + private func internalCount(_ key: Key, node: RedBlackNode, count: inout Int) { + if sentinel !== node { + if key == node.key { + count += 1 + } + + internalCount(key, node: node.left, count: &count) + internalCount(key, node: node.right, count: &count) + } + } + + /** + :name: internalUpdateValue + :description: Traverses the Tree and updates all the values that match the key. + */ + private func internalUpdateValue(_ value: Value?, for key: Key, node: RedBlackNode) { + if node !== sentinel { + if key == node.key { + node.value = value + } + + internalUpdateValue(value, for: key, node: node.left) + internalUpdateValue(value, for: key, node: node.right) + } + } + + /** + :name: internalOrder + :description: Traverses the Tree for the internal order statistic of a key. + - returns: Int + */ + private func internalOrder(_ node: RedBlackNode) -> Int { + var x = node + var r: Int = x.left.order + 1 + + while root !== x { + if x.parent.right === x { + r += x.parent.left.order + 1 + } + x = x.parent + } + + return r + } + + /** + :name: validateOrder + :description: Validates the order statistic being within range of 1...n. + */ + private func validateOrder(_ order: Int) { + assert(order > startIndex || order <= endIndex, "[Algorithm Error: Order out of bounds.]") + } + + public static func ==(lhs: RedBlackTree, rhs: RedBlackTree) -> Bool { + return lhs.count == rhs.count && lhs.elementsEqual(rhs, by: { a, b -> Bool in + return a.key == b.key + }) + } + + public static func !=(lhs: RedBlackTree, rhs: RedBlackTree) -> Bool { + return !(lhs == rhs) + } + + public static func +(lhs: RedBlackTree, rhs: RedBlackTree) -> RedBlackTree { + var t = RedBlackTree() + + for (k, v) in lhs { + t.insert(value: v, for: k) + } + + for (k, v) in rhs { + t.insert(value: v, for: k) + } + + return t + } + + public static func +=(lhs: inout RedBlackTree, rhs: RedBlackTree) { + for (k, v) in rhs { + lhs.insert(value: v, for: k) + } + } + + public static func -(lhs: RedBlackTree, rhs: RedBlackTree) -> RedBlackTree { + var t = rhs + + for (k, _) in rhs { + t.removeValue(for: k) + } + + return t + } + + public static func -=(lhs: inout RedBlackTree, rhs: RedBlackTree) { + for (k, _) in rhs { + lhs.removeValue(for: k) + } + } } -public func +=(lhs: RedBlackTree, rhs: RedBlackTree) { - for (k, v) in rhs { - lhs.insert(k, value: v) - } -} -public func -(lhs: RedBlackTree, rhs: RedBlackTree) -> RedBlackTree { - let t: RedBlackTree = rhs - for (k, _) in rhs { - t.removeValueForKeys(k) - } - return t -} - -public func -=(lhs: RedBlackTree, rhs: RedBlackTree) { - for (k, _) in rhs { - lhs.removeValueForKeys(k) - } -} diff --git a/Sources/SortedDictionary.swift b/Sources/SortedDictionary.swift index d3c25c2..a7e86f3 100644 --- a/Sources/SortedDictionary.swift +++ b/Sources/SortedDictionary.swift @@ -1,433 +1,386 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -public class SortedDictionary : ProbableType, CollectionType, Equatable, CustomStringConvertible { - public typealias Generator = AnyGenerator<(key: Key, value: Value?)> - - /** - Total number of elements within the RedBlackTree - */ - public internal(set) var count: Int = 0 - - /** - :name: tree - :description: Internal storage of (key, value) pairs. - - returns: RedBlackTree - */ - internal var tree: RedBlackTree - - /** - :name: asDictionary - */ - public var asDictionary: Dictionary { - var d: Dictionary = Dictionary() - for (k, v) in self { - d[k] = v - } - return d - } - - /** - :name: description - :description: Conforms to the Printable Protocol. Outputs the - data in the SortedDictionary in a readable format. - - returns: String - */ - public var description: String { - return tree.internalDescription - } - - /** - :name: first - :description: Get the first (key, value) pair. - k1 <= k2 <= K3 ... <= Kn - - returns: (key: Key, value: Value?)? - */ - public var first: (key: Key, value: Value?)? { - return tree.first - } - - /** - :name: last - :description: Get the last (key, value) pair. - k1 <= k2 <= K3 ... <= Kn - - returns: (key: Key, value: Value?)? - */ - public var last: (key: Key, value: Value?)? { - return tree.last - } - - /** - :name: isEmpty - :description: A boolean of whether the SortedDictionary is empty. - - returns: Bool - */ - public var isEmpty: Bool { - return 0 == count - } - - /** - :name: startIndex - :description: Conforms to the CollectionType Protocol. - - returns: Int - */ - public var startIndex: Int { - return 0 - } - - /** - :name: endIndex - :description: Conforms to the CollectionType Protocol. - - returns: Int - */ - public var endIndex: Int { - return count - } - - /** - :name: keys - :description: Returns an array of the key values in order. - - returns: SortedDictionary.SortedKey - */ - public var keys: SortedSet { - let s: SortedSet = SortedSet() - for x in self { - s.insert(x.key) - } - return s - } - - /** - :name: values - :description: Returns an array of the values that are sorted based - on the key ordering. - - returns: SortedDictionary.SortedValue - */ - public var values: Array { - var s: Array = Array() - for x in self { - s.append(x.value!) - } - return s - } - - /** - :name: init - :description: Constructor. - */ - public init() { - tree = RedBlackTree(uniqueKeys: true) - } - - /** - :name: init - :description: Constructor. - - parameter elements: (Key, Value?)... Initiates with a given list of elements. - */ - public convenience init(elements: (Key, Value?)...) { - self.init(elements: elements) - } - - /** - :name: init - :description: Constructor. - - parameter elements: Array<(Key, Value?)> Initiates with a given array of elements. - */ - public convenience init(elements: Array<(Key, Value?)>) { - self.init() - insert(elements) - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes using - // index values [0...n-1]. - // :returns: SortedDictionary.Generator - // - public func generate() -> SortedDictionary.Generator { - var index = startIndex - return AnyGenerator { - if index < self.endIndex { - let i: Int = index - index += 1 - return self[i] - } - return nil - } - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: T...) -> Int { - return countOf(keys) - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: Array) -> Int { - return tree.countOf(keys) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: T...) -> Double { - return probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Array) -> Double { - return tree.probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(block: (key: Key, value: Value?) -> Bool) -> Double { - return tree.probabilityOf(block) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: T...) -> Double { - return expectedValueOf(trials, elements: elements) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Array) -> Double { - return tree.expectedValueOf(trials, elements: elements) - } - - /** - :name: operator [key 1...key n] - :description: Property key mapping. If the key type is a - String, this feature allows access like a - Dictionary. - - returns: Value? - */ - public subscript(key: Key) -> Value? { - get { - return tree[key] - } - set(value) { - tree[key] = value - count = tree.count - } - } - - /** - :name: operator [0...count - 1] - :description: Allows array like access of the index. - Items are kept in order, so when iterating - through the items, they are returned in their - ordered form. - - returns: (key: Key, value: Value?) - */ - public subscript(index: Int) -> (key: Key, value: Value?) { - get { - return tree[index] - } - set(value) { - tree[index] = value - count = tree.count - } - } - - /** - :name: indexOf - :description: Returns the Index of a given member, or -1 if the member is not present in the set. - - returns: Int - */ - public func indexOf(key: Key) -> Int { - return tree.indexOf(key) - } - - /** - :name: insert - :description: Insert a key / value pair. - - returns: Bool - */ - public func insert(key: Key, value: Value?) -> Bool { - let result: Bool = tree.insert(key, value: value) - count = tree.count - return result - } - - /** - :name: insert - :description: Inserts a list of (Key, Value?) pairs. - - parameter elements: (Key, Value?)... Elements to insert. - */ - public func insert(elements: (Key, Value?)...) { - insert(elements) - } - - /** - :name: insert - :description: Inserts an array of (Key, Value?) pairs. - - parameter elements: Array<(Key, Value?)> Elements to insert. - */ - public func insert(elements: Array<(Key, Value?)>) { - tree.insert(elements) - count = tree.count - } - - /** - :name: removeValueForKeys - :description: Removes key / value pairs based on the key value given. - */ - public func removeValueForKeys(keys: Key...) { - removeValueForKeys(keys) - } - - /** - :name: removeValueForKeys - :description: Removes key / value pairs based on the key value given. - */ - public func removeValueForKeys(keys: Array) { - tree.removeValueForKeys(keys) - count = tree.count - } - - /** - :name: removeAll - :description: Remove all nodes from the tree. - */ - public func removeAll() { - tree.removeAll() - count = tree.count - } - - /** - :name: updateValue - :description: Updates a node for the given key value. - */ - public func updateValue(value: Value?, forKey: Key) { - tree.updateValue(value, forKey: forKey) - } - - /** - :name: findValueForKey - :description: Finds the value for key passed. - - parameter key: Key The key to find. - - returns: Value? - */ - public func findValueForKey(key: Key) -> Value? { - return tree.findValueForKey(key) - } - - /** - :name: search - :description: Accepts a list of keys and returns a subset - SortedDictionary with the given values if they exist. - */ - public func search(keys: Key...) -> SortedDictionary { - return search(keys) - } - - /** - :name: search - :description: Accepts an array of keys and returns a subset - SortedDictionary with the given values if they exist. - */ - public func search(keys: Array) -> SortedDictionary { - var dict: SortedDictionary = SortedDictionary() - for key: Key in keys { - traverse(key, node: tree.root, dict: &dict) - } - return dict - } - - /** - :name: traverse - :description: Traverses the SortedDictionary, looking for a key match. - */ - internal func traverse(key: Key, node: RedBlackNode, inout dict: SortedDictionary) { - if tree.sentinel !== node { - if key == node.key { - dict.insert((key, node.value)) - } - traverse(key, node: node.left, dict: &dict) - traverse(key, node: node.right, dict: &dict) - } - } +public struct SortedDictionary: Probable, Collection, BidirectionalCollection, Equatable, CustomStringConvertible { + public typealias Element = RedBlackTree.Element + public typealias ProbableElement = RedBlackTree.ProbableElement + + /// Returns the position immediately after the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be less than + /// `endIndex`. + /// - Returns: The index value immediately after `i`. + public func index(after i: Int) -> Int { + return i + 1 + } + + public func index(before i: Int) -> Int { + return i - 1 + } + + public typealias Iterator = AnyIterator + + /// Total number of elements within the RedBlackTree + public internal(set) var count = 0 + + /// Internal storage of (key, value) pairs. + internal var tree: RedBlackTree + + /// Get the data as a Dictionary. + public var asDictionary: [Key: Value?] { + var d = [Key: Value?]() + for (k, v) in self { + d[k] = v + } + return d + } + + /// Conforms to the Printable Protocol. Outputs the + public var description: String { + return tree.description + } + + /// Conforms to the Collection Protocol. + public var startIndex: Int { + return 0 + } + + /// Conforms to the Collection Protocol. + public var endIndex: Int { + return count + } + + /// Retrieves an Array of the key values in order. + public var keys: [Key] { + return tree.keys + } + + /// Retrieves an Array of the values that are sorted based + public var values: [Value] { + return tree.values + } + + /// Initializer. + public init() { + tree = RedBlackTree(uniqueKeys: true) + } + + /** + Initializes with a given list of elements. + - Parameter elements: A list of (key, value) pairs. + */ + public init(elements: (Key, Value?)...) { + self.init(elements: elements) + } + + /** + Initializes with a given Array of elements. + - Parameter elements: An Array of (key, value) pairs. + */ + public init(elements: [(Key, Value?)]) { + self.init() + insert(elements) + } + + fileprivate init(tree : RedBlackTree) { + self.init() + self.tree = tree + } + + public func _customIndexOfEquatableElement(_ element: Key) -> Int?? { + return nil + } + + public func makeIterator() -> Iterator { + var i = indices.makeIterator() + return AnyIterator { i.next().map { self[$0] } } + } + + /** + Retrieves the total count of instances for the given + keys. + - Parameter of keys: A list of Key types. + - Returns: An Int. + */ + public func count(of keys: Key...) -> Int { + return count(of: keys) + } + + /** + Retrieves the total count of instances for the given + keys. + - Parameter of keys: An Array of Key types. + - Returns: An Int. + */ + public func count(of keys: [Key]) -> Int { + return tree.count(of: keys) + } + + /** + Calculates the probability of the given keys. + - Parameter of keys: A list of Key types. + - Returns: A Double. + */ + public func probability(of keys: Key...) -> Double { + return probability(of: keys) + } + + /** + Calculates the probability of the given keys. + - Parameter of keys: An Array of Key types. + - Returns: A Double. + */ + public func probability(of keys: [Key]) -> Double { + return tree.probability(of: keys) + } + + /** + Calculates the probability using a block. + - Parameter execute block: A block function to execute. + - Returns: A Double. + */ + public func probability(execute block: (Key, Value?) -> Bool) -> Double { + return tree.probability(execute: block) + } + + /** + The expected value of given keys based on a number of trials. + - Parameter trials: An Int. + - Parameter for keys: A list of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for keys: Key...) -> Double { + return expectedValue(trials: trials, for: keys) + } + + /** + The expected value of given keys based on a number of trials. + - Parameter trials: An Int. + - Parameter for keys: A list of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for keys: [Key]) -> Double { + return tree.expectedValue(trials: trials, for: keys) + } + + /** + Property key mapping. If the key type is a String, this feature + allows access like a Dictionary. + - Parameter key: A Key type. + - Returns: An optional Value type. + */ + public subscript(key: Key) -> Value? { + get { + return tree[key] + } + set(value) { + tree[key] = value + count = tree.count + } + } + + public subscript(position: Int) -> Key { + return self[position].key + } + + /** + Allows Array like access of the index. Items are kept in order, + so when iterating through the items, they are returned in their + ordered form. + - Parameter index: An Int. + - Returns: A (key: Key, value: Value?) + */ + public subscript(index: Int) -> (key: Key, value: Value?) { + get { + return tree[index] + } + set(value) { + tree[index] = value + count = tree.count + } + } + + /** + Returns the Index of a given member, or -1 if the member is not + present. + - Parameter of key: A Key type. + - Returns: An Int. + */ + public func index(of key: Key) -> Int { + return tree.index(of: key) + } + + /** + Insert a key / value pair. + - Parameter value: An optional Value type. + - Parameter for key: A Key type. + - Returns: A boolean of the result, true if inserted, false + otherwise. + */ + @discardableResult + mutating public func insert(value: Value?, for key: Key) -> Bool { + let result = tree.insert(value: value, for: key) + count = tree.count + return result + } + + /** + Inserts a list of key / value pairs. + - Parameter elements: A list of (Key, Value?) tuples. + */ + mutating public func insert(_ elements: (Key, Value?)...) { + insert(elements) + } + + /** + Inserts an Array of key / value pairs. + - Parameter elements: An Array of (Key, Value?) tuples. + */ + mutating public func insert(_ elements: [(Key, Value?)]) { + tree.insert(elements) + count = tree.count + } + + /** + Removes key / value pairs based on the keys given. + - Parameter for keys: A list of Key types. + */ + mutating public func removeValue(for keys: Key...) { + removeValue(for: keys) + } + + /** + Removes key / value pairs based on the keys given. + - Parameter for keys: An Array of Key types. + */ + mutating public func removeValue(for keys: [Key]) { + tree.removeValue(for: keys) + count = tree.count + } + + /// Removes all key / value pairs. + mutating public func removeAll() { + tree.removeAll() + count = tree.count + } + + /** + Updates a vlue for the given key. + - Parameter value: An optional Value type. + - Parameter for key: A Key type. + */ + mutating public func update(value: Value?, for key: Key) { + tree.update(value: value, for: key) + } + + /** + Finds the value for a given key. + - Parameter for key: A Key type. + - Returns: An optional Value type. + */ + public func findValue(for key: Key) -> Value? { + return tree.findValue(for: key) + } + + /** + Finds the value for a key which is less or equal given. + - Parameter for key: A Key type. + - Returns: An optional Value type. + */ + public func findLowerEntry(for key: Key) -> Value? { + return tree.findLowerValue(for: key) + } + + /** + Finds the value for a key which is larger or equal given. + - Parameter for key: A Key type. + - Returns: An optional Value type. + */ + public func findCeilingEntry(for key: Key) -> Value? { + return tree.findCeilingValue(for: key) + } + + /** + Searches for given keys in the SortedDictionary. + - Parameter for keys: A list of Key types. + - Returns: A SortedDictionary. + */ + public func search(for keys: Key...) -> SortedDictionary { + return search(for: keys) + } + + /** + Searches for given keys in the SortedDictionary. + - Parameter for keys: An Array of Key types. + - Returns: A SortedDictionary. + */ + public func search(for keys: [Key]) -> SortedDictionary { + var d = SortedDictionary() + for key in keys { + traverse(for: key, node: tree.root, dictionary: &d) + } + return d + } + + /** + Traverses the SortedDictionary, looking for a key matches. + - Parameter for key: A Key type. + - Parameter node: A RedBlackNode. + - Parameter dictionary: A SortedDictionary to map the results too. + */ + internal func traverse(for key: Key, node: RedBlackNode, dictionary: inout SortedDictionary) { + guard tree.sentinel !== node else { + return + } + + if key == node.key { + dictionary.insert(value: node.value, for: key) + } + + traverse(for: key, node: node.left, dictionary: &dictionary) + traverse(for: key, node: node.right, dictionary: &dictionary) + } + + static public func ==(lhs: SortedDictionary, rhs: SortedDictionary) -> Bool { + return lhs.tree == rhs.tree + } + + static public func +(lhs: SortedDictionary, rhs: SortedDictionary) -> SortedDictionary { + return SortedDictionary(tree : lhs.tree + rhs.tree) + } + + static public func +=(lhs: inout SortedDictionary, rhs: SortedDictionary) { + lhs.tree += rhs.tree + } + + static public func -(lhs: SortedDictionary, rhs: SortedDictionary) -> SortedDictionary { + return SortedDictionary(tree : lhs.tree - rhs.tree) + } + + static public func -=(lhs: inout SortedDictionary, rhs: SortedDictionary) { + lhs.tree -= rhs.tree + } } -public func ==(lhs: SortedDictionary, rhs: SortedDictionary) -> Bool { - if lhs.count != rhs.count { - return false - } - for i in 0..(lhs: SortedDictionary, rhs: SortedDictionary) -> Bool { - return !(lhs == rhs) -} - -public func +(lhs: SortedDictionary, rhs: SortedDictionary) -> SortedDictionary { - let t: SortedDictionary = lhs - for (k, v) in rhs { - t.insert(k, value: v) - } - return t -} - -public func +=(lhs: SortedDictionary, rhs: SortedDictionary) { - for (k, v) in rhs { - lhs.insert(k, value: v) - } -} - -public func -(lhs: SortedDictionary, rhs: SortedDictionary) -> SortedDictionary { - let t: SortedDictionary = lhs - for (k, _) in rhs { - t.removeValueForKeys(k) - } - return t -} - -public func -=(lhs: SortedDictionary, rhs: SortedDictionary) { - for (k, _) in rhs { - lhs.removeValueForKeys(k) - } -} diff --git a/Sources/SortedMultiDictionary.swift b/Sources/SortedMultiDictionary.swift index aefb24c..b2ccc4c 100644 --- a/Sources/SortedMultiDictionary.swift +++ b/Sources/SortedMultiDictionary.swift @@ -1,433 +1,402 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -public class SortedMultiDictionary : ProbableType, CollectionType, Equatable, CustomStringConvertible { - public typealias Generator = AnyGenerator<(key: Key, value: Value?)> - - /** - Total number of elements within the RedBlackTree - */ - public internal(set) var count: Int = 0 - - /** - :name: tree - :description: Internal storage of (key, value) pairs. - - returns: RedBlackTree - */ - internal var tree: RedBlackTree - - /** - :name: asDictionary - */ - public var asDictionary: Dictionary { - var d: Dictionary = Dictionary() - for (k, v) in self { - d[k] = v - } - return d - } - - /** - :name: description - :description: Conforms to the Printable Protocol. Outputs the - data in the SortedMultiDictionary in a readable format. - - returns: String - */ - public var description: String { - return tree.internalDescription - } - - /** - :name: first - :description: Get the first (key, value) pair. - k1 <= k2 <= K3 ... <= Kn - - returns: (key: Key, value: Value?)? - */ - public var first: (key: Key, value: Value?)? { - return tree.first - } - - /** - :name: last - :description: Get the last (key, value) pair. - k1 <= k2 <= K3 ... <= Kn - - returns: (key: Key, value: Value?)? - */ - public var last: (key: Key, value: Value?)? { - return tree.last - } - - /** - :name: isEmpty - :description: A boolean of whether the SortedMultiDictionary is empty. - - returns: Bool - */ - public var isEmpty: Bool { - return 0 == count - } - - /** - :name: startIndex - :description: Conforms to the CollectionType Protocol. - - returns: Int - */ - public var startIndex: Int { - return 0 - } - - /** - :name: endIndex - :description: Conforms to the CollectionType Protocol. - - returns: Int - */ - public var endIndex: Int { - return count - } - - /** - :name: keys - :description: Returns an array of the key values in ordered. - */ - public var keys: SortedMultiSet { - let s: SortedMultiSet = SortedMultiSet() - for x in self { - s.insert(x.key) - } - return s - } - - /** - :name: values - :description: Returns an array of the values that are ordered based - on the key ordering. - */ - public var values: Array { - var s: Array = Array() - for x in self { - s.append(x.value!) - } - return s - } - - /** - :name: init - :description: Constructor. - */ - public init() { - tree = RedBlackTree(uniqueKeys: false) - } - - /** - :name: init - :description: Constructor. - - parameter elements: (Key, Value?)... Initiates with a given list of elements. - */ - public convenience init(elements: (Key, Value?)...) { - self.init(elements: elements) - } - - /** - :name: init - :description: Constructor. - - parameter elements: Array<(Key, Value?)> Initiates with a given array of elements. - */ - public convenience init(elements: Array<(Key, Value?)>) { - self.init() - insert(elements) - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes using - // index values [0...n-1]. - // :returns: SortedMultiDictionary.Generator - // - public func generate() -> SortedMultiDictionary.Generator { - var index = startIndex - return AnyGenerator { - if index < self.endIndex { - let i: Int = index - index += 1 - return self[i] - } - return nil - } - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: T...) -> Int { - return countOf(keys) - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: Array) -> Int { - return tree.countOf(keys) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: T...) -> Double { - return probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Array) -> Double { - return tree.probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(block: (key: Key, value: Value?) -> Bool) -> Double { - return tree.probabilityOf(block) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: T...) -> Double { - return expectedValueOf(trials, elements: elements) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Array) -> Double { - return tree.expectedValueOf(trials, elements: elements) - } - - /** - :name: operator [key 1...key n] - :description: Property key mapping. If the key type is a - String, this feature allows access like a - Dictionary. - - returns: Value? - */ - public subscript(key: Key) -> Value? { - get { - return tree[key] - } - set(value) { - tree[key] = value - count = tree.count - } - } - - /** - :name: operator [0...count - 1] - :description: Allows array like access of the index. - Items are kept in order, so when iterating - through the items, they are returned in their - ordered form. - - returns: (key: Key, value: Value?) - */ - public subscript(index: Int) -> (key: Key, value: Value?) { - get { - return tree[index] - } - set(value) { - tree[index] = value - count = tree.count - } - } - - /** - :name: indexOf - :description: Returns the Index of a given member, or -1 if the member is not present in the set. - - returns: Int - */ - public func indexOf(key: Key) -> Int { - return tree.indexOf(key) - } - - /** - :name: insert - :description: Insert a key / value pair. - - returns: Bool - */ - public func insert(key: Key, value: Value?) -> Bool { - let result: Bool = tree.insert(key, value: value) - count = tree.count - return result - } - - /** - :name: insert - :description: Inserts a list of (Key, Value?) pairs. - - parameter elements: (Key, Value?)... Elements to insert. - */ - public func insert(elements: (Key, Value?)...) { - insert(elements) - } - - /** - :name: insert - :description: Inserts an array of (Key, Value?) pairs. - - parameter elements: Array<(Key, Value?)> Elements to insert. - */ - public func insert(elements: Array<(Key, Value?)>) { - tree.insert(elements) - count = tree.count - } - - /** - :name: removeValueForKeys - :description: Removes key / value pairs based on the key value given. - - returns: SortedMultiDictionary? - */ - public func removeValueForKeys(keys: Key...) { - removeValueForKeys(keys) - } - - /** - :name: removeValueForKeys - :description: Removes key / value pairs based on the key value given. - */ - public func removeValueForKeys(keys: Array) { - tree.removeValueForKeys(keys) - count = tree.count - } - - /** - :name: removeAll - :description: Remove all nodes from the tree. - */ - public func removeAll() { - tree.removeAll() - count = tree.count - } - - /** - :name: updateValue - :description: Updates a node for the given key value. - All keys matching the given key value will be updated. - */ - public func updateValue(value: Value?, forKey: Key) { - tree.updateValue(value, forKey: forKey) - } - - /** - :name: findValueForKey - :description: Finds the value for key passed. - - parameter key: Key The key to find. - - returns: Value? - */ - public func findValueForKey(key: Key) -> Value? { - return tree.findValueForKey(key) - } - - /** - :name: search - :description: Accepts a list of keys and returns a subset - SortedMultiDictionary with the given values if they exist. - */ - public func search(keys: Key...) -> SortedMultiDictionary { - return search(keys) - } - - /** - :name: search - :description: Accepts an array of keys and returns a subset - SortedMultiDictionary with the given values if they exist. - */ - public func search(keys: Array) -> SortedMultiDictionary { - var dict: SortedMultiDictionary = SortedMultiDictionary() - for key: Key in keys { - traverse(key, node: tree.root, dict: &dict) - } - return dict - } - - /** - :name: traverse - :description: Traverses the SortedMultiDictionary, looking for a key match. - */ - internal func traverse(key: Key, node: RedBlackNode, inout dict: SortedMultiDictionary) { - if tree.sentinel !== node { - if key == node.key { - dict.insert((key, node.value)) - } - traverse(key, node: node.left, dict: &dict) - traverse(key, node: node.right, dict: &dict) - } - } +public struct SortedMultiDictionary: Probable, Collection, Equatable, CustomStringConvertible where Key: Hashable { + public typealias Element = RedBlackTree.Element + + /// Returns the position immediately after the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be less than + /// `endIndex`. + /// - Returns: The index value immediately after `i`. + public func index(after i: Int) -> Int { + return i < endIndex ? i + 1 : 0 + } + + public typealias Iterator = AnyIterator<(key: Key, value: Value?)> + + /// Total number of elements within the RedBlackTree + public internal(set) var count = 0 + + /// Internal storage of (key, value) pairs. + internal var tree: RedBlackTree + + /// Get the data as a Dictionary. + public var asDictionary: [Key: Value?] { + var d = [Key: Value?]() + + for (k, v) in self { + d[k] = v + } + + return d + } + + /// Conforms to the Printable Protocol. Outputs the + public var description: String { + return tree.description + } + + /// Get the first (key, value) pair. + public var first: (key: Key, value: Value?)? { + return tree.first + } + + /// Get the last (key, value) pair. + public var last: (key: Key, value: Value?)? { + return tree.last + } + + /// A boolean of whether the SortedMultiDictionary is empty. + public var isEmpty: Bool { + return 0 == count + } + + /// Conforms to the Collection Protocol. + public var startIndex: Int { + return 0 + } + + /// Conforms to the Collection Protocol. + public var endIndex: Int { + return count + } + + /// Retrieves an Array of the key values in order. + public var keys: [Key] { + return tree.keys + } + + /// Retrieves an Array of the values that are sorted based + public var values: [Value] { + return tree.values + } + + /// Initializer. + public init() { + tree = RedBlackTree(uniqueKeys: false) + } + + /** + Initializes with a given list of elements. + - Parameter elements: A list of (key, value) pairs. + */ + public init(elements: (Key, Value?)...) { + self.init(elements: elements) + } + + /** + Initializes with a given Array of elements. + - Parameter elements: An Array of (key, value) pairs. + */ + public init(elements: [(Key, Value?)]) { + self.init() + insert(elements) + } + + public func _customIndexOfEquatableElement(_ element: Key) -> Int?? { + return nil + } + + public func makeIterator() -> SortedMultiDictionary.Iterator { + var i = indices.makeIterator() + return AnyIterator { i.next().map { self[$0] } } + } + + /** + Retrieves the total count of instances for the given + keys. + - Parameter of keys: A list of Key types. + - Returns: An Int. + */ + public func count(of keys: Key...) -> Int { + return count(of: keys) + } + + /** + Retrieves the total count of instances for the given + keys. + - Parameter of keys: An Array of Key types. + - Returns: An Int. + */ + public func count(of keys: [Key]) -> Int { + return tree.count(of: keys) + } + + /** + Calculates the probability of the given keys. + - Parameter of keys: A list of Key types. + - Returns: A Double. + */ + public func probability(of keys: Key...) -> Double { + return probability(of: keys) + } + + /** + Calculates the probability of the given keys. + - Parameter of keys: An Array of Key types. + - Returns: A Double. + */ + public func probability(of keys: [Key]) -> Double { + return tree.probability(of: keys) + } + + /** + Calculates the probability using a block. + - Parameter execute block: A block function to execute. + - Returns: A Double. + */ + public func probability(execute block: (Key, Value?) -> Bool) -> Double { + return tree.probability(execute: block) + } + + /** + The expected value of given keys based on a number of trials. + - Parameter trials: An Int. + - Parameter for keys: A list of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for keys: Key...) -> Double { + return expectedValue(trials: trials, for: keys) + } + + /** + The expected value of given keys based on a number of trials. + - Parameter trials: An Int. + - Parameter for keys: A list of Elements. + - Returns: A Double. + */ + public func expectedValue(trials: Int, for keys: [Key]) -> Double { + return tree.expectedValue(trials: trials, for: keys) + } + + /** + Property key mapping. If the key type is a String, this feature + allows access like a Dictionary. + - Parameter key: A Key type. + - Returns: An optional Value type. + */ + public subscript(key: Key) -> Value? { + get { + return tree[key] + } + set(value) { + tree[key] = value + count = tree.count + } + } + + /** + Returns the Key value at a given position. + - Parameter position: An Int. + - Returns: A Key. + */ + public subscript(position: Int) -> Key { + return tree[position] + } + + /** + Allows Array like access of the index. Items are kept in order, + so when iterating through the items, they are returned in their + ordered form. + - Parameter index: An Int. + - Returns: A (key: Key, value: Value?) + */ + public subscript(index: Int) -> (key: Key, value: Value?) { + get { + return tree[index] + } + set(value) { + tree[index] = value + count = tree.count + } + } + + /** + Returns the Index of a given member, or -1 if the member is not + present. + - Parameter of key: A Key type. + - Returns: An Int. + */ + public func index(of key: Key) -> Int { + return tree.index(of: key) + } + + /** + Insert a key / value pair. + - Parameter value: An optional Value type. + - Parameter for key: A Key type. + - Returns: A boolean of the result, true if inserted, false + otherwise. + */ + @discardableResult + mutating public func insert(value: Value?, for key: Key) -> Bool { + let result = tree.insert(value: value, for: key) + count = tree.count + return result + } + + /** + Inserts a list of key / value pairs. + - Parameter elements: A list of (Key, Value?) tuples. + */ + mutating public func insert(_ elements: (Key, Value?)...) { + insert(elements) + } + + /** + Inserts an Array of key / value pairs. + - Parameter elements: An Array of (Key, Value?) tuples. + */ + mutating public func insert(_ elements: [(Key, Value?)]) { + tree.insert(elements) + count = tree.count + } + + /** + Removes key / value pairs based on the keys given. + - Parameter for keys: A list of Key types. + */ + mutating public func removeValue(for keys: Key...) { + removeValue(for: keys) + } + + /** + Removes key / value pairs based on the keys given. + - Parameter for keys: An Array of Key types. + */ + mutating public func removeValue(for keys: [Key]) { + tree.removeValue(for: keys) + count = tree.count + } + + /// Removes all key / value pairs. + mutating public func removeAll() { + tree.removeAll() + count = tree.count + } + + /** + Updates a vlue for the given key. + - Parameter value: An optional Value type. + - Parameter for key: A Key type. + */ + mutating public func update(value: Value?, for key: Key) { + tree.update(value: value, for: key) + } + + /** + Finds the value for a given key. + - Parameter for key: A Key type. + - Returns: An optional Value type. + */ + public func findValue(for key: Key) -> Value? { + return tree.findValue(for: key) + } + + /** + Searches for given keys in the SortedMultiDictionary. + - Parameter for keys: A list of Key types. + - Returns: A SortedMultiDictionary. + */ + public func search(for keys: Key...) -> SortedMultiDictionary { + return search(for: keys) + } + + /** + Searches for given keys in the SortedMultiDictionary. + - Parameter for keys: An Array of Key types. + - Returns: A SortedMultiDictionary. + */ + public func search(for keys: [Key]) -> SortedMultiDictionary { + var d = SortedMultiDictionary() + for key in keys { + traverse(for: key, node: tree.root, dictionary: &d) + } + return d + } + + /** + Traverses the SortedMultiDictionary, looking for a key matches. + - Parameter for key: A Key type. + - Parameter node: A RedBlackNode. + - Parameter dictionary: A SortedMultiDictionary to map the results too. + */ + internal func traverse(for key: Key, node: RedBlackNode, dictionary: inout SortedMultiDictionary) { + guard tree.sentinel !== node else { + return + } + + if key == node.key { + dictionary.insert(value: node.value, for: key) + } + + traverse(for: key, node: node.left, dictionary: &dictionary) + traverse(for: key, node: node.right, dictionary: &dictionary) + } } -public func ==(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> Bool { - if lhs.count != rhs.count { - return false - } - for i in 0..(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> Bool { + if lhs.count != rhs.count { + return false + } + for i in 0..(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> Bool { - return !(lhs == rhs) +public func !=(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> Bool { + return !(lhs == rhs) } -public func +(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> SortedMultiDictionary { - let t: SortedMultiDictionary = lhs - for (k, v) in rhs { - t.insert(k, value: v) - } - return t +public func +(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> SortedMultiDictionary { + var t = SortedMultiDictionary() + for (k, v) in lhs { + t.insert(value: v, for: k) + } + for (k, v) in rhs { + t.insert(value: v, for: k) + } + return t } -public func +=(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) { - for (k, v) in rhs { - lhs.insert(k, value: v) - } +public func +=(lhs: inout SortedMultiDictionary, rhs: SortedMultiDictionary) { + for (k, v) in rhs { + lhs.insert(value: v, for: k) + } } -public func -(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> SortedMultiDictionary { - let t: SortedMultiDictionary = lhs - for (k, _) in rhs { - t.removeValueForKeys(k) - } - return t +public func -(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) -> SortedMultiDictionary { + var t = lhs + t.removeValue(for: rhs.keys) + return t } -public func -=(lhs: SortedMultiDictionary, rhs: SortedMultiDictionary) { - for (k, _) in rhs { - lhs.removeValueForKeys(k) - } +public func -=(lhs: inout SortedMultiDictionary, rhs: SortedMultiDictionary) { + lhs.removeValue(for: rhs.keys) } diff --git a/Sources/SortedMultiSet.swift b/Sources/SortedMultiSet.swift index 8247a35..a2d9b7e 100644 --- a/Sources/SortedMultiSet.swift +++ b/Sources/SortedMultiSet.swift @@ -1,679 +1,663 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -public class SortedMultiSet : ProbableType, CollectionType, Comparable, Equatable, CustomStringConvertible { - public typealias Generator = AnyGenerator - - /** - Total number of elements within the RedBlackTree - */ - public internal(set) var count: Int = 0 - - /** - :name: tree - :description: Internal storage of elements. - - returns: RedBlackTree - */ - internal var tree: RedBlackTree - - /** - :name: asArray - */ - public var asArray: Array { - var a: Array = Array() - for x in self { - a.append(x) - } - return a - } - - /** - :name: description - :description: Conforms to the Printable Protocol. Outputs the - data in the SortedMultiSet in a readable format. - - returns: String - */ - public var description: String { - var output: String = "[" - let l: Int = count - 1 - for i in 0..(uniqueKeys: false) - } - - /** - :name: init - :description: Constructor - */ - public convenience init(elements: Element...) { - self.init(elements: elements) - } - - /** - :name: init - :description: Constructor - */ - public convenience init(elements: Array) { - self.init() - insert(elements) - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes using - // index values [0...n-1]. - // :returns: SortedMultiSet.Generator - // - public func generate() -> SortedMultiSet.Generator { - var index = startIndex - return AnyGenerator { - if index < self.endIndex { - let i: Int = index - index += 1 - return self[i] - } - return nil - } - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: T...) -> Int { - return countOf(keys) - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: Array) -> Int { - return tree.countOf(keys) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: T...) -> Double { - return probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Array) -> Double { - return tree.probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(block: (element: Element) -> Bool) -> Double { - if 0 == count { - return 0 - } - - var c: Int = 0 - for x in self { - if block(element: x) { - c += 1 - } - } - return Double(c) / Double(count) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: T...) -> Double { - return expectedValueOf(trials, elements: elements) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Array) -> Double { - return tree.expectedValueOf(trials, elements: elements) - } - - /** - :name: operator [0...count - 1] - :description: Allows array like access of the index. - Items are kept in order, so when iterating - through the items, they are returned in their - ordered form. - - returns: Element - */ - public subscript(index: Int) -> Element { - return tree[index].key - } - - /** - :name: indexOf - :description: Returns the Index of a given member, or -1 if the member is not present in the set. - - returns: Int - */ - public func indexOf(element: Element) -> Int { - return tree.indexOf(element) - } - - /** - :name: contains - :description: A boolean check if values exists - in the set. - - returns: Bool - */ - public func contains(elements: Element...) -> Bool { - return contains(elements) - } - - /** - :name: contains - :description: A boolean check if an array of values exist - in the set. - - returns: Bool - */ - public func contains(elements: Array) -> Bool { - if 0 == elements.count { - return false - } - for x in elements { - if nil == tree.findValueForKey(x) { - return false - } - } - return true - } - - /** - :name: insert - :description: Inserts new elements into the SortedMultiSet. - */ - public func insert(elements: Element...) { - insert(elements) - } - - /** - :name: insert - :description: Inserts new elements into the SortedMultiSet. - */ - public func insert(elements: Array) { - for x in elements { - tree.insert(x, value: x) - } - count = tree.count - } - - /** - :name: remove - :description: Removes elements from the SortedMultiSet. - */ - public func remove(elements: Element...) { - remove(elements) - } - - /** - :name: remove - :description: Removes elements from the SortedMultiSet. - */ - public func remove(elements: Array) { - tree.removeValueForKeys(elements) - count = tree.count - } - - /** - :name: removeAll - :description: Remove all nodes from the tree. - */ - public func removeAll() { - tree.removeAll() - count = tree.count - } - - /** - :name: intersect - :description: Return a new set with elements common to this set and a finite sequence of Sets. - - returns: SortedMultiSet - */ - public func intersect(set: SortedMultiSet) -> SortedMultiSet { - let s: SortedMultiSet = SortedMultiSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - i += 1 - } else if y < x { - j += 1 - } else { - s.insert(x) - i += 1 - j += 1 - } - } - return s - } - - /** - :name: intersectInPlace - :description: Insert elements of a finite sequence of Sets. - */ - public func intersectInPlace(set: SortedMultiSet) { - let l = set.count - if 0 == l { - removeAll() - } else { - var i: Int = 0 - var j: Int = 0 - while count > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - tree.removeInstanceValueForKey(x) - count = tree.count - } else if y < x { - j += 1 - } else { - i += 1 - j += 1 - } - } - } - } - - /** - :name: union - :description: Return a new Set with items in both this set and a finite sequence of Sets. - - returns: SortedMultiSet - */ - public func union(set: SortedMultiSet) -> SortedMultiSet { - let s: SortedMultiSet = SortedMultiSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - s.insert(x) - i += 1 - } else if y < x { - s.insert(y) - j += 1 - } else { - s.insert(x) - i += 1 - j += 1 - } - } - while k > i { - s.insert(self[i]) - i += 1 - } - while l > j { - s.insert(set[j]) - j += 1 - } - return s - } - - /** - :name: unionInPlace - :description: Return a new Set with items in both this set and a finite sequence of Sets. - */ - public func unionInPlace(set: SortedMultiSet) { - var i: Int = 0 - var j: Int = 0 - let l: Int = set.count - while count > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - i += 1 - } else if y < x { - insert(y) - j += 1 - } else { - i += 1 - j += 1 - } - } - while l > j { - insert(set[j]) - j += 1 - } - } - - /** - :name: subtract - :description: Return a new set with elements in this set that do not occur in a finite sequence of Sets. - - returns: SortedMultiSet - */ - public func subtract(set: SortedMultiSet) -> SortedMultiSet { - let s: SortedMultiSet = SortedMultiSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - s.insert(x) - i += 1 - } else if y < x { - j += 1 - } else { - i += 1 - j += 1 - } - } - while k > i { - s.insert(self[i]) - i += 1 - } - return s - } - - /** - :name: subtractInPlace - :description: Remove all elements in the set that occur in a finite sequence of Sets. - */ - public func subtractInPlace(set: SortedMultiSet) { - var i: Int = 0 - var j: Int = 0 - let l: Int = set.count - while count > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - i += 1 - } else if y < x { - j += 1 - } else { - tree.removeInstanceValueForKey(x) - count = tree.count - j += 1 - } - } - } - - /** - :name: exclusiveOr - :description: Return a new set with elements that are either in the set or a finite sequence but do not occur in both. - - returns: SortedMultiSet - */ - public func exclusiveOr(set: SortedMultiSet) -> SortedMultiSet { - let s: SortedMultiSet = SortedMultiSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - s.insert(x) - i += 1 - } else if y < x { - s.insert(y) - j += 1 - } else { - i += countOf(x) - j += set.countOf(y) - } - } - while k > i { - s.insert(self[i]) - i += 1 - } - while l > j { - s.insert(set[j]) - j += 1 - } - return s - } - - /** - :name: exclusiveOrInPlace - :description: For each element of a finite sequence, remove it from the set if it is a - common element, otherwise add it to the set. Repeated elements of the sequence will be - ignored. - */ - public func exclusiveOrInPlace(set: SortedMultiSet) { - var i: Int = 0 - var j: Int = 0 - let l: Int = set.count - while count > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - i += 1 - } else if y < x { - insert(y) - j += 1 - } else { - remove(x) - j += 1 - } - } - while l > j { - insert(set[j]) - j += 1 - } - } - - /** - :name: isDisjointWith - :description: Returns true if no elements in the set are in a finite sequence of Sets. - - returns: Bool - */ - public func isDisjointWith(set: SortedMultiSet) -> Bool { - var i: Int = count - 1 - var j: Int = set.count - 1 - while 0 <= i && 0 <= j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - j -= 1 - } else if y < x { - i -= 1 - } else { - return false - } - } - return true - } - - /** - :name: isSubsetOf - :description: Returns true if the set is a subset of a finite sequence as a Set. - - returns: Bool - */ - public func isSubsetOf(set: SortedMultiSet) -> Bool { - if count > set.count { - return false - } - for x in self { - if !set.contains(x) { - return false - } - } - return true - } - - /** - :name: isStrictSubsetOf - :description: Returns true if the set is a subset of a finite sequence as a Set but not equal. - - returns: Bool - */ - public func isStrictSubsetOf(set: SortedMultiSet) -> Bool { - return count < set.count && isSubsetOf(set) - } - - /** - :name: isSupersetOf - :description: Returns true if the set is a superset of a finite sequence as a Set. - - returns: Bool - */ - public func isSupersetOf(set: SortedMultiSet) -> Bool { - if count < set.count { - return false - } - for x in set { - if !contains(x) { - return false - } - } - return true - } - - /** - :name: isStrictSupersetOf - :description: Returns true if the set is a superset of a finite sequence as a Set but not equal. - - returns: Bool - */ - public func isStrictSupersetOf(set: SortedMultiSet) -> Bool { - return count > set.count && isSupersetOf(set) - } +public struct SortedMultiSet: Probable, Collection, Equatable, CustomStringConvertible where T: Hashable { + public typealias Element = T + + /// Returns the position immediately after the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be less than + /// `endIndex`. + /// - Returns: The index value immediately after `i`. + public func index(after i: Int) -> Int { + return i < endIndex ? i + 1 : 0 + } + + public typealias Iterator = AnyIterator + + /** + Total number of elements within the RedBlackTree + */ + public internal(set) var count = 0 + + /** + :name: tree + :description: Internal storage of elements. + - returns: RedBlackTree + */ + internal var tree: RedBlackTree + + /** + :name: asArray + */ + public var asArray: [Element] { + var a = [Element]() + for x in self { + a.append(x) + } + return a + } + + /** + :name: description + :description: Conforms to the Printable Protocol. Outputs the + data in the SortedMultiSet in a readable format. + - returns: String + */ + public var description: String { + return "[" + map { "\($0)" }.joined(separator: ", ") + "]" + } + + /** + :name: first + :description: Get the first node value in the tree, this is + the first node based on the order of keys where + k1 <= k2 <= K3 ... <= Kn + - returns: Element? + */ + public var first: Element? { + return tree.first?.value + } + + /** + :name: last + :description: Get the last node value in the tree, this is + the last node based on the order of keys where + k1 <= k2 <= K3 ... <= Kn + - returns: Element? + */ + public var last: Element? { + return tree.last?.value + } + + /** + :name: isEmpty + :description: A boolean of whether the RedBlackTree is empty. + - returns: Bool + */ + public var isEmpty: Bool { + return 0 == count + } + + /** + :name: startIndex + :description: Conforms to the Collection Protocol. + - returns: Int + */ + public var startIndex: Int { + return 0 + } + + /** + :name: endIndex + :description: Conforms to the Collection Protocol. + - returns: Int + */ + public var endIndex: Int { + return count + } + + /** + :name: init + :description: Constructor + */ + public init() { + tree = RedBlackTree(uniqueKeys: false) + } + + /** + :name: init + :description: Constructor + */ + public init(elements: Element...) { + self.init(elements: elements) + } + + /** + :name: init + :description: Constructor + */ + public init(elements: [Element]) { + self.init() + insert(elements) + } + + // + // :name: generate + // :description: Conforms to the SequenceType Protocol. Returns + // the next value in the sequence of nodes using + // index values [0...n-1]. + // :returns: SortedMultiSet.Generator + // + public func makeIterator() -> SortedMultiSet.Iterator { + var i = indices.makeIterator() + return AnyIterator { i.next().map { self[$0] } } + } + + /** + Conforms to Probable protocol. + */ + public func count(of elements: T...) -> Int { + return count(of: elements) + } + + /** + Conforms to Probable protocol. + */ + public func count(of elements: [T]) -> Int { + return tree.count(of: elements) + } + + /** + The probability of elements. + */ + public func probability(of elements: T...) -> Double { + return probability(of: elements) + } + + /** + The probability of elements. + */ + public func probability(of elements: [T]) -> Double { + return tree.probability(of: elements) + } + + /** + The probability of elements. + */ + public func probability(execute block: (Element) -> Bool) -> Double { + return tree.probability { (k, _) -> Bool in + return block(k) + } + } + + /** + The expected value of elements. + */ + public func expectedValue(trials: Int, for elements: T...) -> Double { + return expectedValue(trials: trials, for: elements) + } + + /** + The expected value of elements. + */ + public func expectedValue(trials: Int, for elements: [T]) -> Double { + return tree.expectedValue(trials: trials, for: elements) + } + + /** + :name: operator [0...count - 1] + :description: Allows array like access of the index. + Items are kept in order, so when iterating + through the items, they are returned in their + ordered form. + - returns: Element + */ + public subscript(index: Int) -> Element { + return tree[index].key + } + + + /** + :name: indexOf + :description: Returns the Index of a given member, or -1 if the member is not present in the set. + - returns: Int + */ + public func index(of element: Element) -> Int { + return tree.index(of: element) + } + + /** + :name: contains + :description: A boolean check if values exists + in the set. + - returns: Bool + */ + public func contains(_ elements: Element...) -> Bool { + return contains(elements) + } + + /** + :name: contains + :description: A boolean check if an array of values exist + in the set. + - returns: Bool + */ + public func contains(_ elements: [Element]) -> Bool { + if 0 == elements.count { + return false + } + for x in elements { + if nil == tree.findValue(for: x) { + return false + } + } + return true + } + + /** + :name: insert + :description: Inserts new elements into the SortedMultiSet. + */ + mutating public func insert(_ elements: Element...) { + insert(elements) + } + + /** + :name: insert + :description: Inserts new elements into the SortedSet. + */ + mutating public func insert(_ elements: [Element]) { + for x in elements { + tree.insert(value: x, for: x) + } + count = tree.count + } + + /** + :name: remove + :description: Removes elements from the SortedSet. + */ + mutating public func remove(_ elements: Element...) { + remove(elements) + } + + /** + :name: remove + :description: Removes elements from the SortedSet. + */ + mutating public func remove(_ elements: [Element]) { + tree.removeValue(for: elements) + count = tree.count + } + + /** + :name: removeAll + :description: Remove all nodes from the tree. + */ + mutating public func removeAll() { + tree.removeAll() + count = tree.count + } + + /** + :name: intersect + :description: Return a new set with elements common to this set and a finite sequence of Sets. + - returns: SortedMultiSet + */ + public func intersection(_ other: SortedMultiSet) -> SortedMultiSet { + var s = SortedMultiSet() + var i = 0 + var j = 0 + let k: Int = count + let l: Int = other.count + while k > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + i += 1 + } else if y < x { + j += 1 + } else { + s.insert(x) + i += 1 + j += 1 + } + } + return s + } + + /** + :name: formIntersection + :description: Insert elements of a finite sequence of Sets. + */ + mutating public func formIntersection(_ other: SortedMultiSet) { + let l = other.count + if 0 == l { + removeAll() + } else { + var i = 0 + var j = 0 + while count > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + _ = tree.removeInstanceValueForKey(x) + count = tree.count + } else if y < x { + j += 1 + } else { + i += 1 + j += 1 + } + } + } + } + + /** + :name: union + :description: Return a new Set with items in both this set and a finite sequence of Sets. + - returns: SortedMultiSet + */ + public func union(_ other: SortedMultiSet) -> SortedMultiSet { + var s = SortedMultiSet() + var i = 0 + var j = 0 + let k: Int = count + let l: Int = other.count + while k > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + s.insert(x) + i += 1 + } else if y < x { + s.insert(y) + j += 1 + } else { + s.insert(x) + i += 1 + j += 1 + } + } + while k > i { + s.insert(self[i]) + i += 1 + } + while l > j { + s.insert(other[j]) + j += 1 + } + return s + } + + /** + :name: unionInPlace + :description: Return a new Set with items in both this set and a finite sequence of Sets. + */ + mutating public func formUnion(_ other: SortedMultiSet) { + var i = 0 + var j = 0 + let l: Int = other.count + while count > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + i += 1 + } else if y < x { + insert(y) + j += 1 + } else { + i += 1 + j += 1 + } + } + while l > j { + insert(other[j]) + j += 1 + } + } + + /** + :name: subtract + :description: Return a new set with elements in this set that do not occur in a finite sequence of Sets. + - returns: SortedMultiSet + */ + public func subtracting(_ other: SortedMultiSet) -> SortedMultiSet { + var s = SortedMultiSet() + var i = 0 + var j = 0 + let k: Int = count + let l: Int = other.count + while k > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + s.insert(x) + i += 1 + } else if y < x { + j += 1 + } else { + i += 1 + j += 1 + } + } + while k > i { + s.insert(self[i]) + i += 1 + } + return s + } + + /** + :name: subtract + :description: Remove all elements in the set that occur in a finite sequence of Sets. + */ + mutating public func subtract(_ other: SortedMultiSet) { + var i = 0 + var j = 0 + let l: Int = other.count + while count > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + i += 1 + } else if y < x { + j += 1 + } else { + _ = tree.removeInstanceValueForKey(x) + count = tree.count + j += 1 + } + } + } + + /** + :name: exclusiveOr + :description: Return a new set with elements that are either in the set or a finite sequence but do not occur in both. + - returns: SortedMultiSet + */ + public func symmetricDifference(_ other: SortedMultiSet) -> SortedMultiSet { + var s = SortedMultiSet() + var i = 0 + var j = 0 + let k: Int = count + let l: Int = other.count + while k > i && l > j { + let x: Element = self[i] + let y: Element = other[j] + if x < y { + s.insert(x) + i += 1 + } else if y < x { + s.insert(y) + j += 1 + } else { + i += count(of: x) + j += other.count(of: y) + } + } + while k > i { + s.insert(self[i]) + i += 1 + } + while l > j { + s.insert(other[j]) + j += 1 + } + return s + } + + /** + :name: exclusiveOrInPlace + :description: For each element of a finite sequence, remove it from the set if it is a + common element, otherwise add it to the set. Repeated elements of the sequence will be + ignored. + */ + mutating public func formSymmetricDifference(_ other: SortedMultiSet) { + var i = 0 + var j = 0 + let l: Int = other.count + while count > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + i += 1 + } else if y < x { + insert(y) + j += 1 + } else { + remove(x) + j += 1 + } + } + while l > j { + insert(other[j]) + j += 1 + } + } + + /** + :name: isDisjointWith + :description: Returns true if no elements in the set are in a finite sequence of Sets. + - returns: Bool + */ + public func isDisjoint(with other: SortedMultiSet) -> Bool { + var i: Int = count - 1 + var j: Int = other.count - 1 + while 0 <= i && 0 <= j { + let x = self[i] + let y = other[j] + if x < y { + j -= 1 + } else if y < x { + i -= 1 + } else { + return false + } + } + return true + } + + /** + :name: isSubsetOf + :description: Returns true if the set is a subset of a finite sequence as a Set. + - returns: Bool + */ + public func isSubset(of other: SortedMultiSet) -> Bool { + if count > other.count { + return false + } + for x in self { + if !other.contains(x) { + return false + } + } + return true + } + + /** + :name: isStrictSubsetOf + :description: Returns true if the set is a subset of a finite sequence as a Set but not equal. + - returns: Bool + */ + public func isStrictSubset(of other: SortedMultiSet) -> Bool { + return count < other.count && isSubset(of: other) + } + + /** + :name: isSupersetOf + :description: Returns true if the set is a superset of a finite sequence as a Set. + - returns: Bool + */ + public func isSuperset(of other: SortedMultiSet) -> Bool { + if count < other.count { + return false + } + for x in other { + if !contains(x) { + return false + } + } + return true + } + + /** + :name: isStrictSupersetOf + :description: Returns true if the set is a superset of a finite sequence as a Set but not equal. + - returns: Bool + */ + public func isStrictSuperset(of other: SortedMultiSet) -> Bool { + return count > other.count && isSuperset(of: other) + } } -public func ==(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { - if lhs.count != rhs.count { - return false - } - for i in 0..(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { + if lhs.count != rhs.count { + return false + } + for i in 0..(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { - return !(lhs == rhs) +public func !=(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { + return !(lhs == rhs) } -public func +(lhs: SortedMultiSet, rhs: SortedMultiSet) -> SortedMultiSet { - return lhs.union(rhs) +public func +(lhs: SortedMultiSet, rhs: SortedMultiSet) -> SortedMultiSet { + return lhs.union(rhs) } -public func +=(lhs: SortedMultiSet, rhs: SortedMultiSet) { - lhs.unionInPlace(rhs) +public func +=(lhs: inout SortedMultiSet, rhs: SortedMultiSet) { + lhs.formUnion(rhs) } -public func -(lhs: SortedMultiSet, rhs: SortedMultiSet) -> SortedMultiSet { - return lhs.subtract(rhs) +public func -(lhs: SortedMultiSet, rhs: SortedMultiSet) -> SortedMultiSet { + return lhs.subtracting(rhs) } -public func -=(lhs: SortedMultiSet, rhs: SortedMultiSet) { - lhs.subtractInPlace(rhs) +public func -=(lhs: inout SortedMultiSet, rhs: SortedMultiSet) { + lhs.subtract(rhs) } -public func <=(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { - return lhs.isSubsetOf(rhs) +public func <=(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { + return lhs.isSubset(of: rhs) } -public func >=(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { - return lhs.isSupersetOf(rhs) +public func >=(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { + return lhs.isSuperset(of: rhs) } -public func >(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { - return lhs.isStrictSupersetOf(rhs) +public func >(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { + return lhs.isStrictSuperset(of: rhs) } -public func <(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { - return lhs.isStrictSubsetOf(rhs) +public func <(lhs: SortedMultiSet, rhs: SortedMultiSet) -> Bool { + return lhs.isStrictSubset(of: rhs) } diff --git a/Sources/SortedSet.swift b/Sources/SortedSet.swift index 75e8fd6..d9b8906 100644 --- a/Sources/SortedSet.swift +++ b/Sources/SortedSet.swift @@ -1,662 +1,625 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -public class SortedSet : ProbableType, CollectionType, Comparable, Equatable, CustomStringConvertible { - public typealias Generator = AnyGenerator - - /** - Total number of elements within the RedBlackTree - */ - public internal(set) var count: Int = 0 - - /** - :name: tree - :description: Internal storage of elements. - - returns: RedBlckTree - */ - internal var tree: RedBlackTree - - /** - :name: asArray - */ - public var asArray: Array { - var a: Array = Array() - for x in self { - a.append(x) - } - return a - } - - /** - :name: description - :description: Conforms to the Printable Protocol. Outputs the - data in the SortedSet in a readable format. - - returns: String - */ - public var description: String { - var output: String = "[" - let l: Int = count - 1 - for i in 0..(uniqueKeys: true) - } - - /** - :name: init - :description: Constructor. - */ - public convenience init(elements: Element...) { - self.init(elements: elements) - } - - /** - :name: init - :description: Constructor. - */ - public convenience init(elements: Array) { - self.init() - insert(elements) - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes using - // index values [0...n-1]. - // :returns: SortedSet.Generator - // - public func generate() -> SortedSet.Generator { - var index = startIndex - return AnyGenerator { - if index < self.endIndex { - let i: Int = index - index += 1 - return self[i] - } - return nil - } - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: T...) -> Int { - return countOf(keys) - } - - /** - Conforms to ProbableType protocol. - */ - public func countOf(keys: Array) -> Int { - return tree.countOf(keys) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: T...) -> Double { - return probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(elements: Array) -> Double { - return tree.probabilityOf(elements) - } - - /** - The probability of elements. - */ - public func probabilityOf(block: (element: Element) -> Bool) -> Double { - if 0 == count { - return 0 - } - - var c: Int = 0 - for x in self { - if block(element: x) { - c += 1 - } - } - return Double(c) / Double(count) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: T...) -> Double { - return expectedValueOf(trials, elements: elements) - } - - /** - The expected value of elements. - */ - public func expectedValueOf(trials: Int, elements: Array) -> Double { - return tree.expectedValueOf(trials, elements: elements) - } - - /** - :name: operator [0...count - 1] - :description: Allows array like access of the index. - Items are kept in order, so when iterating - through the items, they are returned in their - ordered form. - - returns: Element - */ - public subscript(index: Int) -> Element { - return tree[index].key - } - - /** - :name: indexOf - :description: Returns the Index of a given member, or -1 if the member is not present in the set. - - returns: Int - */ - public func indexOf(element: Element) -> Int { - return tree.indexOf(element) - } - - /** - :name: contains - :description: A boolean check if values exists - in the set. - - returns: Bool - */ - public func contains(elements: Element...) -> Bool { - return contains(elements) - } - - /** - :name: contains - :description: A boolean check if an array of values exist - in the set. - - returns: Bool - */ - public func contains(elements: Array) -> Bool { - if 0 == elements.count { - return false - } - for x in elements { - if nil == tree.findValueForKey(x) { - return false - } - } - return true - } - - /** - :name: insert - :description: Inserts new elements into the SortedSet. - */ - public func insert(elements: Element...) { - insert(elements) - } - - /** - :name: insert - :description: Inserts new elements into the SortedSet. - */ - public func insert(elements: Array) { - for x in elements { - tree.insert(x, value: x) - } - count = tree.count - } - - /** - :name: remove - :description: Removes elements from the SortedSet. - */ - public func remove(elements: Element...) { - remove(elements) - } - - /** - :name: remove - :description: Removes elements from the SortedSet. - */ - public func remove(elements: Array) { - tree.removeValueForKeys(elements) - count = tree.count - } - - /** - :name: removeAll - :description: Remove all nodes from the tree. - */ - public func removeAll() { - tree.removeAll() - count = tree.count - } - - /** - :name: intersect - :description: Return a new set with elements common to this set and a finite sequence of Sets. - - returns: SortedSet - */ - public func intersect(set: SortedSet) -> SortedSet { - let s: SortedSet = SortedSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - i += 1 - } else if y < x { - j += 1 - } else { - s.insert(x) - i += 1 - j += 1 - } - } - return s - } - - /** - :name: intersectInPlace - :description: Insert elements of a finite sequence of Sets. - */ - public func intersectInPlace(set: SortedSet) { - let l = set.count - if 0 == l { - removeAll() - } else { - var i: Int = 0 - var j: Int = 0 - while count > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - remove(x) - } else if y < x { - j += 1 - } else { - i += 1 - j += 1 - } - } - } - } - - /** - :name: union - :description: Return a new Set with items in both this set and a finite sequence of Sets. - - returns: SortedSet - */ - public func union(set: SortedSet) -> SortedSet { - let s: SortedSet = SortedSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - s.insert(x) - i += 1 - } else if y < x { - s.insert(y) - j += 1 - } else { - s.insert(x) - i += 1 - j += 1 - } - } - while k > i { - s.insert(self[i]) - i += 1 - } - while l > j { - s.insert(set[j]) - j += 1 - } - return s - } - - /** - :name: unionInPlace - :description: Return a new Set with items in both this set and a finite sequence of Sets. - */ - public func unionInPlace(set: SortedSet) { - var j: Int = set.count - while 0 != j { - j -= 1 - insert(set[j]) - } - } - - /** - :name: subtract - :description: Return a new set with elements in this set that do not occur in a finite sequence of Sets. - - returns: SortedSet - */ - public func subtract(set: SortedSet) -> SortedSet { - let s: SortedSet = SortedSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - s.insert(x) - i += 1 - } else if y < x { - j += 1 - } else { - i += 1 - j += 1 - } - } - while k > i { - s.insert(self[i]) - i += 1 - } - return s - } - - /** - :name: subtractInPlace - :description: Remove all elements in the set that occur in a finite sequence of Sets. - */ - public func subtractInPlace(set: SortedSet) { - var i: Int = 0 - var j: Int = 0 - let l: Int = set.count - while count > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - i += 1 - } else if y < x { - j += 1 - } else { - remove(x) - j += 1 - } - } - } - - /** - :name: exclusiveOr - :description: Return a new set with elements that are either in the set or a finite sequence but do not occur in both. - - returns: SortedSet - */ - public func exclusiveOr(set: SortedSet) -> SortedSet { - let s: SortedSet = SortedSet() - var i: Int = 0 - var j: Int = 0 - let k: Int = count - let l: Int = set.count - while k > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - s.insert(x) - i += 1 - } else if y < x { - s.insert(y) - j += 1 - } else { - i += 1 - j += 1 - } - } - while k > i { - s.insert(self[i]) - i += 1 - } - while l > j { - s.insert(set[j]) - j += 1 - } - return s - } - - /** - :name: exclusiveOrInPlace - :description: For each element of a finite sequence, remove it from the set if it is a - common element, otherwise add it to the set. Repeated elements of the sequence will be - ignored. - */ - public func exclusiveOrInPlace(set: SortedSet) { - var i: Int = 0 - var j: Int = 0 - let l: Int = set.count - while count > i && l > j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - i += 1 - } else if y < x { - insert(y) - j += 1 - } else { - remove(x) - j += 1 - } - } - while l > j { - insert(set[j]) - j += 1 - } - } - - /** - :name: isDisjointWith - :description: Returns true if no elements in the set are in a finite sequence of Sets. - - returns: Bool - */ - public func isDisjointWith(set: SortedSet) -> Bool { - var i: Int = count - 1 - var j: Int = set.count - 1 - while 0 <= i && 0 <= j { - let x: Element = self[i] - let y: Element = set[j] - if x < y { - j -= 1 - } else if y < x { - i -= 1 - } else { - return false - } - } - return true - } - - /** - :name: isSubsetOf - :description: Returns true if the set is a subset of a finite sequence as a Set. - - returns: Bool - */ - public func isSubsetOf(set: SortedSet) -> Bool { - if count > set.count { - return false - } - for x in self { - if !set.contains(x) { - return false - } - } - return true - } - - /** - :name: isStrictSubsetOf - :description: Returns true if the set is a subset of a finite sequence as a Set but not equal. - - returns: Bool - */ - public func isStrictSubsetOf(set: SortedSet) -> Bool { - return count < set.count && isSubsetOf(set) - } - - /** - :name: isSupersetOf - :description: Returns true if the set is a superset of a finite sequence as a Set. - - returns: Bool - */ - public func isSupersetOf(set: SortedSet) -> Bool { - if count < set.count { - return false - } - for x in set { - if !contains(x) { - return false - } - } - return true - } - - /** - :name: isStrictSupersetOf - :description: Returns true if the set is a superset of a finite sequence as a Set but not equal. - - returns: Bool - */ - public func isStrictSupersetOf(set: SortedSet) -> Bool { - return count > set.count && isSupersetOf(set) - } +public struct SortedSet: Probable, Collection, Equatable, CustomStringConvertible where T: Hashable { + public typealias Element = T + + /// Returns the position immediately after the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be less than + /// `endIndex`. + /// - Returns: The index value immediately after `i`. + public func index(after i: Int) -> Int { + return i < endIndex ? i + 1 : 0 + } + + public typealias Iterator = AnyIterator + + /** + Total number of elements within the RedBlackTree + */ + public internal(set) var count = 0 + + /** + :name: tree + :description: Internal storage of elements. + - returns: RedBlckTree + */ + internal var tree: RedBlackTree + + /** + :name: asArray + */ + public var asArray: [Element] { + return map { $0 } + } + + /** + :name: description + :description: Conforms to the Printable Protocol. Outputs the + data in the SortedSet in a readable format. + - returns: String + */ + public var description: String { + return "[" + map { "\($0)" }.joined(separator: ",") + "]" + } + + /** + :name: first + :description: Get the first node value in the tree, this is + the first node based on the order of keys where + k1 <= k2 <= K3 ... <= Kn + - returns: Element? + */ + public var first: Element? { + return tree.first?.value + } + + /** + :name: last + :description: Get the last node value in the tree, this is + the last node based on the order of keys where + k1 <= k2 <= K3 ... <= Kn + - returns: Element? + */ + public var last: Element? { + return tree.last?.value + } + + /** + :name: startIndex + :description: Conforms to the Collection Protocol. + - returns: Int + */ + public var startIndex: Int { + return 0 + } + + /** + :name: endIndex + :description: Conforms to the Collection Protocol. + - returns: Int + */ + public var endIndex: Int { + return count + } + + /** + :name: init + :description: Constructor. + */ + public init() { + tree = RedBlackTree(uniqueKeys: true) + } + + /** + :name: init + :description: Constructor. + */ + public init(elements: Element...) { + self.init(elements: elements) + } + + /** + :name: init + :description: Constructor. + */ + public init(elements: [Element]) { + self.init() + insert(elements) + } + + public func makeIterator() -> SortedSet.Iterator { + var i = indices.makeIterator() + return AnyIterator { i.next().map { self[$0] } } + } + + /** + Conforms to Probable protocol. + */ + public func count(of elements: Element...) -> Int { + return count(of: elements) + } + + /** + Conforms to Probable protocol. + */ + public func count(of elements: [Element]) -> Int { + return tree.count(of: elements) + } + + /** + The probability of elements. + */ + public func probability(of elements: Element...) -> Double { + return probability(of: elements) + } + + /** + The probability of elements. + */ + public func probability(of elements: [Element]) -> Double { + return tree.probability(of: elements) + } + + /** + The probability of elements. + */ + public func probability(execute block: (Element) -> Bool) -> Double { + return tree.probability { (k, _) -> Bool in + return block(k) + } + } + + /** + The expected value of elements. + */ + public func expectedValue(trials: Int, for elements: Element...) -> Double { + return expectedValue(trials: trials, for: elements) + } + + /** + The expected value of elements. + */ + public func expectedValue(trials: Int, for elements: [Element]) -> Double { + return tree.expectedValue(trials: trials, for: elements) + } + + /** + :name: operator [0...count - 1] + :description: Allows array like access of the index. + Items are kept in order, so when iterating + through the items, they are returned in their + ordered form. + - returns: Element + */ + public subscript(index: Int) -> Element { + return tree[index].key + } + + /** + :name: indexOf + :description: Returns the Index of a given member, or -1 if the member is not present in the set. + - returns: Int + */ + public func index(of element: Element) -> Int { + return tree.index(of: element) + } + + /** + :name: contains + :description: A boolean check if values exists + in the set. + - returns: Bool + */ + public func contains(_ elements: Element...) -> Bool { + return contains(elements) + } + + /** + :name: contains + :description: A boolean check if an array of values exist + in the set. + - returns: Bool + */ + public func contains(_ elements: [Element]) -> Bool { + if 0 == elements.count { + return false + } + for x in elements { + if nil == tree.findValue(for: x) { + return false + } + } + return true + } + + /** + :name: insert + :description: Inserts new elements into the SortedSet. + */ + mutating public func insert(_ elements: Element...) { + insert(elements) + } + + /** + :name: insert + :description: Inserts new elements into the SortedSet. + */ + mutating public func insert(_ elements: [Element]) { + for x in elements { + tree.insert(value: x, for: x) + } + count = tree.count + } + + /** + :name: remove + :description: Removes elements from the SortedSet. + */ + mutating public func remove(_ elements: Element...) { + remove(elements) + } + + /** + :name: remove + :description: Removes elements from the SortedSet. + */ + mutating public func remove(_ elements: [Element]) { + tree.removeValue(for: elements) + count = tree.count + } + + /** + :name: removeAll + :description: Remove all nodes from the tree. + */ + mutating public func removeAll() { + tree.removeAll() + count = tree.count + } + + /** + :name: intersect + :description: Return a new set with elements common to this set and a finite sequence of Sets. + - returns: SortedSet + */ + public func intersection(_ other: SortedSet) -> SortedSet { + var s = SortedSet() + var i = 0 + var j = 0 + let k = count + let l = other.count + while k > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + i += 1 + } else if y < x { + j += 1 + } else { + s.insert(x) + i += 1 + j += 1 + } + } + return s + } + + /** + :name: formIntersection + :description: Insert elements of a finite sequence of Sets. + */ + mutating public func formIntersection(_ other: SortedSet) { + let l = other.count + if 0 == l { + removeAll() + } else { + var i = 0 + var j = 0 + while count > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + remove(x) + } else if y < x { + j += 1 + } else { + i += 1 + j += 1 + } + } + } + } + + /** + :name: union + :description: Return a new Set with items in both this set and a finite sequence of Sets. + - returns: SortedSet + */ + public func union(_ other: SortedSet) -> SortedSet { + var s = SortedSet() + var i = 0 + var j = 0 + let k = count + let l = other.count + while k > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + s.insert(x) + i += 1 + } else if y < x { + s.insert(y) + j += 1 + } else { + s.insert(x) + i += 1 + j += 1 + } + } + while k > i { + s.insert(self[i]) + i += 1 + } + while l > j { + s.insert(other[j]) + j += 1 + } + return s + } + + /** + :name: unionInPlace + :description: Return a new Set with items in both this set and a finite sequence of Sets. + */ + mutating public func formUnion(_ other: SortedSet) { + var a = [Element]() + other.forEach { + a.append($0) + } + insert(a) + } + + /** + :name: subtract + :description: Return a new set with elements in this set that do not occur in a finite sequence of Sets. + - returns: SortedSet + */ + public func subtracting(_ other: SortedSet) -> SortedSet { + var s = SortedSet() + var i = 0 + var j = 0 + let k = count + let l = other.count + while k > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + s.insert(x) + i += 1 + } else if y < x { + j += 1 + } else { + i += 1 + j += 1 + } + } + while k > i { + s.insert(self[i]) + i += 1 + } + return s + } + + /** + :name: subtract + :description: Remove all elements in the set that occur in a finite sequence of Sets. + */ + mutating public func subtract(_ other: SortedSet) { + var i = 0 + var j = 0 + let l = other.count + while count > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + i += 1 + } else if y < x { + j += 1 + } else { + remove(x) + j += 1 + } + } + } + + /** + :name: exclusiveOr + :description: Return a new set with elements that are either in the set or a finite sequence but do not occur in both. + - returns: SortedSet + */ + public func symmetricDifference(_ other: SortedSet) -> SortedSet { + var s = SortedSet() + var i = 0 + var j = 0 + let k = count + let l = other.count + while k > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + s.insert(x) + i += 1 + } else if y < x { + s.insert(y) + j += 1 + } else { + i += 1 + j += 1 + } + } + while k > i { + s.insert(self[i]) + i += 1 + } + while l > j { + s.insert(other[j]) + j += 1 + } + return s + } + + /** + :name: exclusiveOrInPlace + :description: For each element of a finite sequence, remove it from the set if it is a + common element, otherwise add it to the set. Repeated elements of the sequence will be + ignored. + */ + mutating public func formSymmetricDifference(_ other: SortedSet) { + var i = 0 + var j = 0 + let l = other.count + while count > i && l > j { + let x = self[i] + let y = other[j] + if x < y { + i += 1 + } else if y < x { + insert(y) + j += 1 + } else { + remove(x) + j += 1 + } + } + while l > j { + insert(other[j]) + j += 1 + } + } + + /** + :name: isDisjointWith + :description: Returns true if no elements in the set are in a finite sequence of Sets. + - returns: Bool + */ + public func isDisjoint(with other: SortedSet) -> Bool { + var i = count - 1 + var j = other.count - 1 + while 0 <= i && 0 <= j { + let x = self[i] + let y = other[j] + if x < y { + j -= 1 + } else if y < x { + i -= 1 + } else { + return false + } + } + return true + } + + /** + :name: isSubsetOf + :description: Returns true if the set is a subset of a finite sequence as a Set. + - returns: Bool + */ + public func isSubset(of other: SortedSet) -> Bool { + if count > other.count { + return false + } + for x in self { + if !other.contains(x) { + return false + } + } + return true + } + + /** + :name: isStrictSubsetOf + :description: Returns true if the set is a subset of a finite sequence as a Set but not equal. + - returns: Bool + */ + public func isStrictSubset(of other: SortedSet) -> Bool { + return count < other.count && isSubset(of: other) + } + + /** + :name: isSupersetOf + :description: Returns true if the set is a superset of a finite sequence as a Set. + - returns: Bool + */ + public func isSuperset(of other: SortedSet) -> Bool { + if count < other.count { + return false + } + for x in other { + if !contains(x) { + return false + } + } + return true + } + + /** + :name: isStrictSupersetOf + :description: Returns true if the set is a superset of a finite sequence as a Set but not equal. + - returns: Bool + */ + public func isStrictSuperset(of other: SortedSet) -> Bool { + return count > other.count && isSuperset(of: other) + } } -public func ==(lhs: SortedSet, rhs: SortedSet) -> Bool { - if lhs.count != rhs.count { - return false - } - for i in 0..(lhs: SortedSet, rhs: SortedSet) -> Bool { + if lhs.count != rhs.count { + return false + } + for i in 0..(lhs: SortedSet, rhs: SortedSet) -> Bool { - return !(lhs == rhs) +public func !=(lhs: SortedSet, rhs: SortedSet) -> Bool { + return !(lhs == rhs) } -public func +(lhs: SortedSet, rhs: SortedSet) -> SortedSet { - return lhs.union(rhs) +public func +(lhs: SortedSet, rhs: SortedSet) -> SortedSet { + return lhs.union(rhs) } -public func +=(lhs: SortedSet, rhs: SortedSet) { - lhs.unionInPlace(rhs) +public func +=(lhs: inout SortedSet, rhs: SortedSet) { + lhs.formUnion(rhs) } -public func -(lhs: SortedSet, rhs: SortedSet) -> SortedSet { - return lhs.subtract(rhs) +public func -(lhs: SortedSet, rhs: SortedSet) -> SortedSet { + return lhs.subtracting(rhs) } -public func -=(lhs: SortedSet, rhs: SortedSet) { - lhs.subtractInPlace(rhs) +public func -=(lhs: inout SortedSet, rhs: SortedSet) { + lhs.subtract(rhs) } -public func <=(lhs: SortedSet, rhs: SortedSet) -> Bool { - return lhs.isSubsetOf(rhs) +public func <=(lhs: SortedSet, rhs: SortedSet) -> Bool { + return lhs.isSubset(of: rhs) } -public func >=(lhs: SortedSet, rhs: SortedSet) -> Bool { - return lhs.isSupersetOf(rhs) +public func >=(lhs: SortedSet, rhs: SortedSet) -> Bool { + return lhs.isSuperset(of: rhs) } -public func >(lhs: SortedSet, rhs: SortedSet) -> Bool { - return lhs.isStrictSupersetOf(rhs) +public func >(lhs: SortedSet, rhs: SortedSet) -> Bool { + return lhs.isStrictSuperset(of: rhs) } -public func <(lhs: SortedSet, rhs: SortedSet) -> Bool { - return lhs.isStrictSubsetOf(rhs) +public func <(lhs: SortedSet, rhs: SortedSet) -> Bool { + return lhs.isStrictSubset(of: rhs) } diff --git a/Sources/Stack.swift b/Sources/Stack.swift index 2250c26..ec568af 100644 --- a/Sources/Stack.swift +++ b/Sources/Stack.swift @@ -1,140 +1,104 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ -public class Stack : CustomStringConvertible, SequenceType { - public typealias Generator = AnyGenerator - - /** - :name: list - :description: Underlying data structure. - - returns: DoublyLinkedList - */ - private var list: DoublyLinkedList - - /** - :name: count - :description: Total number of items in the Stack. - - returns: Int - */ - public var count: Int { - return list.count - } - - /** - :name: top - :description: Get the latest element at the top - of the Stack and do not remove - it. - - returns: Element? - */ - public var top: Element? { - return list.front - } - - /** - :name: isEmpty - :description: A boolean of whether the Stack is empty. - - returns: Bool - */ - public var isEmpty: Bool { - return list.isEmpty - } - - /** - :name: description - :description: Conforms to the Printable Protocol. - - returns: String - */ - public var description: String { - return "Stack" + list.internalDescription - } - - /** - :name: init - :description: Constructor. - */ - public init() { - list = DoublyLinkedList() - } - - // - // :name: generate - // :description: Conforms to the SequenceType Protocol. Returns - // the next value in the sequence of nodes. - // :returns: Stack.Generator - // - public func generate() -> Stack.Generator { - return list.generate() - } - - /** - :name: push - :description: Insert a new element at the top of the Stack. - */ - public func push(element: Element) { - list.insertAtFront(element) - } - - /** - :name: pop - :description: Get the latest element at the top of - the Stack and remove it from the - Stack. - - returns: Element? - */ - public func pop() -> Element? { - return list.removeAtFront() - } - - /** - :name: removeAll - :description: Remove all elements from the Stack. - */ - public func removeAll() { - list.removeAll() - } +public struct Stack: CustomStringConvertible, Sequence { + public typealias Iterator = AnyIterator + + /// Underlying data structure. + private var list: DoublyLinkedList + + /// Total number of items in the Stack. + public var count: Int { + return list.count + } + + /// Get the latest element at the top of the Stack and do not remove it. + public var top: Element? { + return list.front + } + + /// A boolean of whether the Stack is empty. + public var isEmpty: Bool { + return list.isEmpty + } + + /// Conforms to the Printable Protocol. + public var description: String { + return list.description + } + + /// Initializer. + public init() { + list = DoublyLinkedList() + } + + /** + Conforms to the SequenceType Protocol. Returns the next value in the + sequence of nodes. + - Returns: Stack.Generator + */ + public func makeIterator() -> Stack.Iterator { + return list.makeIterator() + } + + /** + Insert a new element at the top of the Stack. + - Parameter _ element: An Element type. + */ + mutating public func push(_ element: Element) { + list.insert(atFront: element) + } + + /** + Get the latest element at the top of the Stack and remove it from + the Stack. + - Returns: Element? + */ + mutating public func pop() -> Element? { + return list.removeAtFront() + } + + /// Remove all elements from the Stack. + mutating public func removeAll() { + list.removeAll() + } } public func +(lhs: Stack, rhs: Stack) -> Stack { - let s: Stack = Stack() - for x in lhs { - s.push(x!) - } - for x in rhs { - s.push(x!) - } - return s + var s = Stack() + for x in lhs { + s.push(x) + } + for x in rhs { + s.push(x) + } + return s } -public func +=(lhs: Stack, rhs: Stack) { - for x in rhs { - lhs.push(x!) - } +public func +=(lhs: inout Stack, rhs: Stack) { + for x in rhs { + lhs.push(x) + } } diff --git a/Tests/DequeTests.swift b/Tests/DequeTests.swift index 25827a3..2a56a34 100644 --- a/Tests/DequeTests.swift +++ b/Tests/DequeTests.swift @@ -1,106 +1,97 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class DequeTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let d: Deque = Deque() - - d.insertAtFront(1) - d.insertAtFront(2) - d.insertAtFront(3) - - XCTAssert(3 == d.count, "Count incorrect, got \(d.count).") - - XCTAssert(3 == d.front, "Front incorrect, got \(d.front)") - XCTAssert(1 == d.back, "Back incorrect, got \(d.back)") - - d.insertAtBack(5) - d.insertAtBack(6) - d.insertAtBack(7) - - XCTAssert(6 == d.count, "Count incorrect, got \(d.count).") - - XCTAssert(3 == d.front, "Front incorrect, got \(d.front)") - XCTAssert(7 == d.back, "Back incorrect, got \(d.back)") - - XCTAssert(3 == d.removeAtFront() && 5 == d.count && 2 == d.front, "RemoveAtFront incorrect") - XCTAssert(2 == d.removeAtFront() && 4 == d.count && 1 == d.front, "RemoveAtFront incorrect") - XCTAssert(1 == d.removeAtFront() && 3 == d.count && 5 == d.front, "RemoveAtFront incorrect") - - XCTAssert(7 == d.removeAtBack() && 2 == d.count && 6 == d.back, "RemoveAtBack incorrect") - XCTAssert(6 == d.removeAtBack() && 1 == d.count && 5 == d.back, "RemoveAtBack incorrect") - XCTAssert(5 == d.removeAtBack() && 0 == d.count && nil == d.back, "RemoveAtBack incorrect") - - d.insertAtFront(1) - d.insertAtFront(2) - d.insertAtFront(3) - d.removeAll() - - XCTAssert(0 == d.count, "Count incorrect, got \(d.count).") - } - - func testConcat() { - let d1: Deque = Deque() - d1.insertAtBack(1) - d1.insertAtBack(2) - d1.insertAtBack(3) - - let d2: Deque = Deque() - d2.insertAtBack(4) - d2.insertAtBack(5) - d2.insertAtBack(6) - - let d3: Deque = d1 + d2 - - for x in d1 { - XCTAssert(x == d3.removeAtFront(), "Concat incorrect.") - } - - for x in d2 { - XCTAssert(x == d3.removeAtFront(), "Concat incorrect.") - } - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var d = Deque() + + d.insert(atFront: 1) + d.insert(atFront: 2) + d.insert(atFront: 3) + + XCTAssert(3 == d.count, "Count incorrect, got \(d.count).") + + XCTAssert(3 == d.front, "Front incorrect, got \(String(describing: d.front))") + XCTAssert(1 == d.back, "Back incorrect, got \(String(describing: d.back))") + + d.insert(atBack: 5) + d.insert(atBack: 6) + d.insert(atBack: 7) + + XCTAssert(6 == d.count, "Count incorrect, got \(d.count).") + + XCTAssert(3 == d.front, "Front incorrect, got \(String(describing: d.front))") + XCTAssert(7 == d.back, "Back incorrect, got \(String(describing: d.back))") + + XCTAssert(3 == d.removeAtFront() && 5 == d.count && 2 == d.front, "RemoveAtFront incorrect") + XCTAssert(2 == d.removeAtFront() && 4 == d.count && 1 == d.front, "RemoveAtFront incorrect") + XCTAssert(1 == d.removeAtFront() && 3 == d.count && 5 == d.front, "RemoveAtFront incorrect") + + XCTAssert(7 == d.removeAtBack() && 2 == d.count && 6 == d.back, "RemoveAtBack incorrect") + XCTAssert(6 == d.removeAtBack() && 1 == d.count && 5 == d.back, "RemoveAtBack incorrect") + XCTAssert(5 == d.removeAtBack() && 0 == d.count && nil == d.back, "RemoveAtBack incorrect") + + d.insert(atFront: 1) + d.insert(atFront: 2) + d.insert(atFront: 3) + d.removeAll() + + XCTAssert(0 == d.count, "Count incorrect, got \(d.count).") + } + + func testConcat() { + var d1 = Deque() + d1.insert(atBack: 1) + d1.insert(atBack: 2) + d1.insert(atBack: 3) + + var d2 = Deque() + d2.insert(atBack: 5) + d2.insert(atBack: 6) + d2.insert(atBack: 7) + + var d3 = d1 + d2 + + for x in d1 { + XCTAssertEqual(x, d3.removeAtFront(), "Concat incorrect.") + } + + for x in d2 { + XCTAssertEqual(x, d3.removeAtFront(), "Concat incorrect.") + } + } } diff --git a/Tests/DoublyLinkedListTests.swift b/Tests/DoublyLinkedListTests.swift index 4384f5b..b5c7c81 100644 --- a/Tests/DoublyLinkedListTests.swift +++ b/Tests/DoublyLinkedListTests.swift @@ -1,169 +1,164 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class DoublyLinkedListTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let l: DoublyLinkedList = DoublyLinkedList() - - l.insertAtFront(1) - l.insertAtFront(2) - l.insertAtFront(3) - - XCTAssert(3 == l.count, "Count incorrect, got \(l.count).") - - XCTAssert(3 == l.front, "Front incorrect, got \(l.front)") - XCTAssert(1 == l.back, "Back incorrect, got \(l.back)") - - l.insertAtBack(5) - l.insertAtBack(6) - l.insertAtBack(7) - - l.cursorToFront() - while !l.isCursorAtBack { - l.next - } - - l.cursorToBack() - while !l.isCursorAtFront { - l.previous - } - - XCTAssert(6 == l.count, "Count incorrect, got \(l.count).") - - XCTAssert(3 == l.front, "Front incorrect, got \(l.front)") - XCTAssert(7 == l.back, "Back incorrect, got \(l.back)") - - l.cursorToFront() - XCTAssert(3 == l.front && l.front == l.cursor, "Current incorrect, got \(l.cursor)") - XCTAssert(2 == l.next, "Test failed, got \(l.cursor)") - XCTAssert(1 == l.next, "Test failed, got \(l.cursor)") - XCTAssert(5 == l.next, "Test failed, got \(l.cursor)") - XCTAssert(6 == l.next, "Test failed, got \(l.cursor)") - XCTAssert(7 == l.next, "Test failed, got \(l.cursor)") - - l.cursorToBack() - XCTAssert(7 == l.back && l.back == l.cursor, "Current incorrect, got \(l.cursor)") - XCTAssert(6 == l.previous, "Test failed, got \(l.cursor)") - XCTAssert(5 == l.previous, "Test failed, got \(l.cursor)") - XCTAssert(1 == l.previous, "Test failed, got \(l.cursor)") - XCTAssert(2 == l.previous, "Test failed, got \(l.cursor)") - XCTAssert(3 == l.previous, "Test failed, got \(l.cursor)") - - l.cursorToFront() - XCTAssert(3 == l.removeAtFront() && 5 == l.count, "Test failed.") - XCTAssert(2 == l.removeAtFront() && 4 == l.count, "Test failed.") - XCTAssert(1 == l.removeAtFront() && 3 == l.count, "Test failed.") - - l.cursorToBack() - XCTAssert(7 == l.removeAtBack() && 2 == l.count, "Test failed.") - XCTAssert(6 == l.removeAtBack() && 1 == l.count, "Test failed.") - XCTAssert(5 == l.removeAtBack() && 0 == l.count, "Test failed.") - - l.removeAll() - l.cursorToFront() - XCTAssert(nil == l.cursor && 0 == l.count, "Test failed, got \(l.cursor)") - l.insertBeforeCursor(1) - XCTAssert(1 == l.cursor && 1 == l.count, "Test failed, got \(l.cursor)") - - l.removeAll() - l.cursorToBack() - XCTAssert(nil == l.cursor && 0 == l.count, "Test failed, got \(l.cursor)") - l.insertAfterCursor(1) - XCTAssert(1 == l.cursor && 1 == l.count, "Test failed, got \(l.cursor)") - - l.removeAll() - l.insertAtBack(1) - XCTAssert(1 == l.cursor && 1 == l.count, "Test failed, got \(l.cursor)") - l.insertAfterCursor(2) - l.insertAfterCursor(6) - l.next - XCTAssert(6 == l.cursor && 3 == l.count, "Test failed, got \(l.cursor)") - l.insertBeforeCursor(3) - l.insertBeforeCursor(5) - l.previous - XCTAssert(5 == l.cursor && 5 == l.count, "Test failed, got \(l.cursor)") - l.insertAtBack(4) - l.previous - l.removeAtCursor() - XCTAssert(5 == l.cursor && 5 == l.count, "Test failed, got \(l.cursor)") - l.removeAtCursor() - XCTAssert(6 == l.cursor && 4 == l.count, "Test failed, got \(l.cursor)") - l.removeAtCursor() - XCTAssert(2 == l.cursor && 3 == l.count, "Test failed, got \(l.cursor)") - l.removeAtCursor() - XCTAssert(1 == l.previous && 2 == l.count, "Test failed, got \(l.cursor)") - l.removeAtCursor() - XCTAssert(l.front == l.cursor && l.back == l.cursor && 1 == l.count, "Test failed, got \(l.cursor)") - l.removeAtCursor() - XCTAssert(nil == l.cursor && 0 == l.count, "Test failed, got \(l.cursor)") - - l.insertAtFront(1) - l.insertAtBack(2) - l.insertAtFront(3) - } - - func testConcat() { - let l1: DoublyLinkedList = DoublyLinkedList() - l1.insertAtFront(3) - l1.insertAtFront(2) - l1.insertAtFront(1) - - let l2: DoublyLinkedList = DoublyLinkedList() - l2.insertAtBack(4) - l2.insertAtBack(5) - l2.insertAtBack(6) - - let l3: DoublyLinkedList = l1 + l2 - - for x in l1 { - XCTAssert(x == l3.removeAtFront(), "Concat incorrect.") - } - - for x in l2 { - XCTAssert(x == l3.removeAtFront(), "Concat incorrect.") - } - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var l = DoublyLinkedList() + + l.insert(atFront: 1) + l.insert(atFront: 2) + l.insert(atFront: 3) + + XCTAssert(3 == l.count, "Count incorrect, got \(l.count).") + + XCTAssert(3 == l.front, "Front incorrect, got \(String(describing: l.front))") + XCTAssert(1 == l.back, "Back incorrect, got \(String(describing: l.back))") + + l.insert(atBack: 5) + l.insert(atBack: 6) + l.insert(atBack: 7) + + l.cursorToFront() + while !l.isCursorAtBack { + l.next() + } + + l.cursorToBack() + while !l.isCursorAtFront { + l.previous() + } + + XCTAssert(6 == l.count, "Count incorrect, got \(l.count).") + + XCTAssert(3 == l.front, "Front incorrect, got \(String(describing: l.front))") + XCTAssert(7 == l.back, "Back incorrect, got \(String(describing: l.back))") + + l.cursorToFront() + XCTAssert(3 == l.front && l.front == l.cursor, "Current incorrect, got \(String(describing: l.cursor))") + XCTAssert(2 == l.next(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(1 == l.next(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(5 == l.next(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(6 == l.next(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(7 == l.next(), "Test failed, got \(String(describing: l.cursor))") + + l.cursorToBack() + XCTAssert(7 == l.back && l.back == l.cursor, "Current incorrect, got \(String(describing: l.cursor))") + XCTAssert(6 == l.previous(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(5 == l.previous(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(1 == l.previous(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(2 == l.previous(), "Test failed, got \(String(describing: l.cursor))") + XCTAssert(3 == l.previous(), "Test failed, got \(String(describing: l.cursor))") + + l.cursorToFront() + XCTAssert(3 == l.removeAtFront() && 5 == l.count, "Test failed.") + XCTAssert(2 == l.removeAtFront() && 4 == l.count, "Test failed.") + XCTAssert(1 == l.removeAtFront() && 3 == l.count, "Test failed.") + + l.cursorToBack() + XCTAssert(7 == l.removeAtBack() && 2 == l.count, "Test failed.") + XCTAssert(6 == l.removeAtBack() && 1 == l.count, "Test failed.") + XCTAssert(5 == l.removeAtBack() && 0 == l.count, "Test failed.") + + l.removeAll() + l.cursorToFront() + XCTAssert(nil == l.cursor && 0 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.insert(beforeCursor: 1) + XCTAssert(1 == l.cursor && 1 == l.count, "Test failed, got \(String(describing: l.cursor))") + + l.removeAll() + l.cursorToBack() + XCTAssert(nil == l.cursor && 0 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.insert(afterCursor: 1) + XCTAssert(1 == l.cursor && 1 == l.count, "Test failed, got \(String(describing: l.cursor))") + + l.removeAll() + l.insert(atBack: 1) + XCTAssert(1 == l.cursor && 1 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.insert(afterCursor: 2) + l.insert(afterCursor: 6) + l.next() + XCTAssert(6 == l.cursor && 3 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.insert(beforeCursor: 3) + l.insert(beforeCursor: 5) + l.previous() + XCTAssert(5 == l.cursor && 5 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.insert(atBack: 4) + l.previous() + l.removeAtCursor() + XCTAssert(5 == l.cursor && 5 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.removeAtCursor() + XCTAssert(6 == l.cursor && 4 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.removeAtCursor() + XCTAssert(2 == l.cursor && 3 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.removeAtCursor() + XCTAssert(1 == l.previous() && 2 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.removeAtCursor() + XCTAssert(l.front == l.cursor && l.back == l.cursor && 1 == l.count, "Test failed, got \(String(describing: l.cursor))") + l.removeAtCursor() + XCTAssert(nil == l.cursor && 0 == l.count, "Test failed, got \(String(describing: l.cursor))") + + l.insert(atFront: 1) + l.insert(atBack: 2) + l.insert(atFront: 3) + } + + func testConcat() { + var l1 = DoublyLinkedList() + l1.insert(atFront: 3) + l1.insert(atFront: 2) + l1.insert(atFront: 1) + + var l2 = DoublyLinkedList() + l2.insert(atBack: 4) + l2.insert(atBack: 5) + l2.insert(atBack: 6) + + var l3 = l1 + l2 + + for x in l1 { + XCTAssert(x == l3.removeAtFront(), "Concat incorrect.") + } + + for x in l2 { + XCTAssert(x == l3.removeAtFront(), "Concat incorrect.") + } + } + + func testPerformance() { + self.measure() {} + } } diff --git a/Tests/ProbabilityTests.swift b/Tests/ProbabilityTests.swift index ea5e4b1..d7b655d 100644 --- a/Tests/ProbabilityTests.swift +++ b/Tests/ProbabilityTests.swift @@ -1,194 +1,189 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class ProbabilityTests: XCTestCase { - var saveExpectation: XCTestExpectation? - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testSortedSet() { - let s: SortedSet = SortedSet() - XCTAssertEqual(0, s.probabilityOf({ _ -> Bool in return true})) - - s.insert(1, 2, 3, 3) - - let ev1: Double = 16 * s.probabilityOf(2, 3) - - XCTAssertEqual(ev1, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - let ev2: Double = 16 * s.probabilityOf { (element: Int) -> Bool in - return 2 == element || 3 == element - } - - XCTAssertEqual(ev2, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - s.removeAll() - XCTAssert(0 == s.count, "Test failed.") - } - - func testSortedMultiSet() { - let s: SortedSet = SortedSet() - XCTAssertEqual(0, s.probabilityOf({ _ -> Bool in return true})) - - s.insert(1, 2, 3, 3) - - let ev1: Double = 16 * s.probabilityOf(2, 3) - - XCTAssertEqual(ev1, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - let ev2: Double = 16 * s.probabilityOf { (element: Int) -> Bool in - return 2 == element || 3 == element - } - - XCTAssertEqual(ev2, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - s.removeAll() - XCTAssert(0 == s.count, "Test failed.") - } - - func testSortedDictionary() { - let s: SortedDictionary = SortedDictionary() - XCTAssertEqual(0, s.probabilityOf({ _ -> Bool in return true})) - - s.insert((1, 1)) - s.insert((2, 2)) - s.insert((3, 3)) - s.insert((3, 3)) - - let ev1: Double = 16 * s.probabilityOf(2, 3) - - XCTAssertEqual(ev1, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - let ev2: Double = 16 * s.probabilityOf { (key: Int, value: Int?) -> Bool in - return 2 == value || 3 == value - } - - XCTAssertEqual(ev2, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - s.removeAll() - XCTAssert(0 == s.count, "Test failed.") - } - - func testSortedMultiDictionary() { - let s: SortedMultiDictionary = SortedMultiDictionary() - XCTAssertEqual(0, s.probabilityOf({ _ -> Bool in return true})) - - s.insert((1, 1)) - s.insert((2, 2)) - s.insert((3, 3)) - s.insert((3, 3)) - - let ev1: Double = 16 * s.probabilityOf(2, 3) - - XCTAssertEqual(ev1, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - let ev2: Double = 16 * s.probabilityOf { (key: Int, value: Int?) -> Bool in - return 2 == value || 3 == value - } - - XCTAssertEqual(ev2, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - s.removeAll() - XCTAssert(0 == s.count, "Test failed.") - } - - func testArray() { - var s: Array = Array() - XCTAssertEqual(0, s.probabilityOf({ _ -> Bool in return true})) - - s.append(1) - s.append(2) - s.append(3) - s.append(4) - - let ev1: Double = 16 * s.probabilityOf(2, 3) - - XCTAssertEqual(ev1, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - let ev2: Double = 16 * s.probabilityOf { (element: Int) -> Bool in - return 2 == element || 3 == element - } - - XCTAssertEqual(ev2, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - s.removeAll() - XCTAssert(0 == s.count, "Test failed.") - } - - func testSet() { - var s: Set = Set() - XCTAssertEqual(0, s.probabilityOf({ _ -> Bool in return true})) - - s.insert(1) - s.insert(2) - s.insert(3) - s.insert(4) - - let ev1: Double = 16 * s.probabilityOf(2, 3) - - XCTAssertEqual(ev1, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - let ev2: Double = 16 * s.probabilityOf { (element: Int) -> Bool in - return 2 == element || 3 == element - } - - XCTAssertEqual(ev2, s.expectedValueOf(16, elements: 2, 3), "Test failed.") - - s.removeAll() - XCTAssertEqual(0, s.count) - } - - func testBlock() { - let die: Array = Array(arrayLiteral: 1, 2, 3, 4, 5, 6) - - let probabilityOfX: Double = die.probabilityOf { (number: Int) in - if 5 < number || 0 == number % 3 { - // Do more. - return true - } - return false - } - - XCTAssertTrue(0.33 < probabilityOfX, "Test failed.") - } - - func testPerformance() { - self.measureBlock() {} - } + var saveExpectation: XCTestExpectation? + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testSortedSet() { + var s = SortedSet() + XCTAssertEqual(0, s.probability { _ -> Bool in return true}) + + s.insert(1, 2, 3, 3) + + let ev1: Double = 16 * s.probability(of: 2, 3) + + XCTAssertEqual(ev1, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + let ev2: Double = 16 * s.probability { (element: Int) -> Bool in + return 2 == element || 3 == element + } + + XCTAssertEqual(ev2, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + s.removeAll() + XCTAssert(0 == s.count, "Test failed.") + } + + func testSortedMultiSet() { + var s = SortedSet() + XCTAssertEqual(0, s.probability { _ -> Bool in return true}) + + s.insert(1, 2, 3, 3) + + let ev1: Double = 16 * s.probability(of: 2, 3) + + XCTAssertEqual(ev1, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + let ev2: Double = 16 * s.probability { (element: Int) -> Bool in + return 2 == element || 3 == element + } + + XCTAssertEqual(ev2, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + s.removeAll() + XCTAssert(0 == s.count, "Test failed.") + } + + func testSortedDictionary() { + var s = SortedDictionary() + XCTAssertEqual(0, s.probability { _, _ -> Bool in return true}) + + s.insert((1, 1)) + s.insert((2, 2)) + s.insert((3, 3)) + s.insert((3, 3)) + + let ev1: Double = 16 * s.probability(of: 2, 3) + + XCTAssertEqual(ev1, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + let ev2: Double = 16 * s.probability { (key: Int, value: Int?) -> Bool in + return 2 == value || 3 == value + } + + XCTAssertEqual(ev2, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + s.removeAll() + XCTAssert(0 == s.count, "Test failed.") + } + + func testSortedMultiDictionary() { + var s = SortedMultiDictionary() + XCTAssertEqual(0, s.probability { _, _ -> Bool in return true}) + + s.insert((1, 1)) + s.insert((2, 2)) + s.insert((3, 3)) + s.insert((3, 3)) + + let ev1: Double = 16 * s.probability(of: 2, 3) + + XCTAssertEqual(ev1, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + let ev2: Double = 16 * s.probability { (key: Int, value: Int?) -> Bool in + return 2 == value || 3 == value + } + + XCTAssertEqual(ev2, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + s.removeAll() + XCTAssert(0 == s.count, "Test failed.") + } + + func testArray() { + var s: Array = Array() + XCTAssertEqual(0, s.probability { _ -> Bool in return true}) + + s.append(1) + s.append(2) + s.append(3) + s.append(4) + + let ev1: Double = 16 * s.probability(of: 2, 3) + + XCTAssertEqual(ev1, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + let ev2: Double = 16 * s.probability { (element: Int) -> Bool in + return 2 == element || 3 == element + } + + XCTAssertEqual(ev2, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + s.removeAll() + XCTAssert(0 == s.count, "Test failed.") + } + + func testSet() { + var s: Set = Set() + XCTAssertEqual(0, s.probability { _ -> Bool in return true}) + + s.insert(1) + s.insert(2) + s.insert(3) + s.insert(4) + + let ev1: Double = 16 * s.probability(of: 2, 3) + + XCTAssertEqual(ev1, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + let ev2: Double = 16 * s.probability { (element: Int) -> Bool in + return 2 == element || 3 == element + } + + XCTAssertEqual(ev2, s.expectedValue(trials: 16, for: 2, 3), "Test failed.") + + s.removeAll() + XCTAssertEqual(0, s.count) + } + + func testBlock() { + let die: Array = Array(arrayLiteral: 1, 2, 3, 4, 5, 6) + + let probabilityOfX: Double = die.probability { (number: Int) in + if 5 < number || 0 == number % 3 { + // Do more. + return true + } + return false + } + + XCTAssertTrue(0.33 < probabilityOfX, "Test failed.") + } + + func testPerformance() { + self.measure() {} + } } diff --git a/Tests/QueueTests.swift b/Tests/QueueTests.swift index 80c9aab..55a8866 100644 --- a/Tests/QueueTests.swift +++ b/Tests/QueueTests.swift @@ -1,111 +1,106 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class QueueTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let q: Queue = Queue() - - q.enqueue(1) - q.enqueue(2) - q.enqueue(3) - - XCTAssert(3 == q.count, "Count incorrect, got \(q.count).") - XCTAssert(1 == q.peek, "Peek incorrect, got \(q.peek)") - - q.enqueue(5) - q.enqueue(6) - q.enqueue(7) - - XCTAssert(6 == q.count, "Count incorrect, got \(q.count).") - XCTAssert(1 == q.peek, "Peek incorrect, got \(q.peek)") - - XCTAssert(1 == q.dequeue() && 5 == q.count && 2 == q.peek, "Dequeue incorrect") - XCTAssert(2 == q.dequeue() && 4 == q.count && 3 == q.peek, "Dequeue incorrect") - XCTAssert(3 == q.dequeue() && 3 == q.count && 5 == q.peek, "Dequeue incorrect") - XCTAssert(5 == q.dequeue() && 2 == q.count && 6 == q.peek, "Dequeue incorrect") - XCTAssert(6 == q.dequeue() && 1 == q.count && 7 == q.peek, "Dequeue incorrect") - XCTAssert(7 == q.dequeue() && 0 == q.count && nil == q.peek, "Dequeue incorrect") - - q.enqueue(1) - q.enqueue(2) - q.enqueue(3) - q.removeAll() - - XCTAssert(0 == q.count, "Count incorrect, got \(q.count).") - - q.enqueue(1) - q.enqueue(2) - q.enqueue(3) - } - - func testConcat() { - let q1: Queue = Queue() - q1.enqueue(1) - q1.enqueue(2) - q1.enqueue(3) - - let q2: Queue = Queue() - q2.enqueue(4) - q2.enqueue(5) - q2.enqueue(6) - - let q3: Queue = q1 + q2 - - for x in q1 { - XCTAssert(x == q3.dequeue(), "Concat incorrect.") - } - - for x in q2 { - XCTAssert(x == q3.dequeue(), "Concat incorrect.") - } - - q3.removeAll() - let q4: Queue = q1 + q2 + q3 - for x in q4 { - XCTAssert(x == q4.dequeue(), "Concat incorrect.") - } - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var q = Queue() + + q.enqueue(1) + q.enqueue(2) + q.enqueue(3) + + XCTAssert(3 == q.count, "Count incorrect, got \(q.count).") + XCTAssert(1 == q.peek, "Peek incorrect, got \(String(describing: q.peek))") + + q.enqueue(5) + q.enqueue(6) + q.enqueue(7) + + XCTAssert(6 == q.count, "Count incorrect, got \(q.count).") + XCTAssert(1 == q.peek, "Peek incorrect, got \(String(describing: q.peek))") + + XCTAssert(1 == q.dequeue() && 5 == q.count && 2 == q.peek, "Dequeue incorrect") + XCTAssert(2 == q.dequeue() && 4 == q.count && 3 == q.peek, "Dequeue incorrect") + XCTAssert(3 == q.dequeue() && 3 == q.count && 5 == q.peek, "Dequeue incorrect") + XCTAssert(5 == q.dequeue() && 2 == q.count && 6 == q.peek, "Dequeue incorrect") + XCTAssert(6 == q.dequeue() && 1 == q.count && 7 == q.peek, "Dequeue incorrect") + XCTAssert(7 == q.dequeue() && 0 == q.count && nil == q.peek, "Dequeue incorrect") + + q.enqueue(1) + q.enqueue(2) + q.enqueue(3) + q.removeAll() + + XCTAssert(0 == q.count, "Count incorrect, got \(q.count).") + + q.enqueue(1) + q.enqueue(2) + q.enqueue(3) + } + + func testConcat() { + var q1 = Queue() + q1.enqueue(1) + q1.enqueue(2) + q1.enqueue(3) + + var q2 = Queue() + q2.enqueue(4) + q2.enqueue(5) + q2.enqueue(6) + + var q3 = q1 + q2 + + for x in q1 { + XCTAssert(x == q3.dequeue(), "Concat incorrect.") + } + + for x in q2 { + XCTAssert(x == q3.dequeue(), "Concat incorrect.") + } + + q3.removeAll() + var q4 = q1 + q2 + q3 + for x in q4 { + XCTAssert(x == q4.dequeue(), "Concat incorrect.") + } + } + + func testPerformance() { + self.measure() {} + } } diff --git a/Tests/RedBlackTreeTests.swift b/Tests/RedBlackTreeTests.swift index 1074027..7878826 100644 --- a/Tests/RedBlackTreeTests.swift +++ b/Tests/RedBlackTreeTests.swift @@ -1,175 +1,171 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class RedBlackTreeTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let s: RedBlackTree = RedBlackTree(uniqueKeys: true) - - XCTAssert(0 == s.count, "Test failed, got \(s.count).") - - for _ in 0..<1000 { - s.insert(1, value: 1) - s.insert(2, value: 2) - s.insert(3, value: 3) - } - - XCTAssert(3 == s.count, "Test failed.\(s)") - XCTAssert(1 == s[0].value, "Test failed.") - XCTAssert(2 == s[1].value, "Test failed.") - XCTAssert(3 == s[2].value, "Test failed.") - - for _ in 0..<500 { - s.removeValueForKeys(1) - s.removeValueForKeys(3) - } - - XCTAssert(1 == s.count, "Test failed.") - s.removeValueForKeys(2) - - XCTAssert(true == s.insert(2, value: 10), "Test failed.") - XCTAssert(1 == s.count, "Test failed.") - XCTAssert(10 == s.findValueForKey(2), "Test failed.") - XCTAssert(10 == s[0].value, "Test failed.") - - s.removeValueForKeys(2) - XCTAssert(0 == s.count, "Test failed.") - - s.insert(1, value: 1) - s.insert(2, value: 2) - s.insert(3, value: 3) - - for i in s.startIndex..> = RedBlackTree>(uniqueKeys: false) - s.insert("friends", value: [1, 2, 3]) - s["menu"] = [11, 22, 33] - - XCTAssert(s["friends"]! == s[0].value!, "Test failed.") - XCTAssert(s["menu"]! == s[1].value!, "Test failed.") - XCTAssert(s["empty"] == nil, "Test failed.") - s["menu"] = [22, 33, 44] - XCTAssert(s["menu"]! == [22, 33, 44], "Test failed.") - s["menu"] = nil - XCTAssert(2 == s.count, "Test failed.") - } - - func testValue() { - let t1: RedBlackTree = RedBlackTree() - t1.insert(1, value: 1) - t1.insert(2, value: 2) - t1.insert(3, value: 3) - - let t2: RedBlackTree = RedBlackTree() - t2.insert(4, value: 4) - t2.insert(5, value: 5) - t2.insert(6, value: 6) - - let t3: RedBlackTree = t1 + t2 - - for i in 0.. = RedBlackTree(uniqueKeys: true) - t1.insert(1, value: 1) - t1.insert(2, value: 2) - t1.insert(3, value: 3) - t1.insert(4, value: 4) - t1.insert(5, value: 5) - t1.insert(5, value: 5) - t1.insert(6, value: 6) - - XCTAssert(0 == t1.indexOf(1), "Test failed.") - XCTAssert(5 == t1.indexOf(6), "Test failed.") - XCTAssert(-1 == t1.indexOf(100), "Test failed.") - } - - func testIndexOfNonUniqueKeys() { - let t1: RedBlackTree = RedBlackTree() - t1.insert(1, value: 1) - t1.insert(2, value: 2) - t1.insert(3, value: 3) - t1.insert(4, value: 4) - t1.insert(5, value: 5) - t1.insert(5, value: 5) - t1.insert(6, value: 6) - - XCTAssert(0 == t1.indexOf(1), "Test failed.") - XCTAssert(6 == t1.indexOf(6), "Test failed.") - XCTAssert(-1 == t1.indexOf(100), "Test failed.") - } - - func testOperands() { - let t1: RedBlackTree = RedBlackTree(uniqueKeys: true) - t1.insert((1, 1), (2, 2), (3, 3), (4, 4)) - XCTAssert(4 == t1.count, "Test failed.") - - let t2: RedBlackTree = RedBlackTree(uniqueKeys: true) - t2.insert((5, 5), (6, 6), (7, 7), (8, 8)) - XCTAssert(4 == t2.count, "Test failed.") - - let t3: RedBlackTree = t1 + t2 - XCTAssert(8 == t3.count, "Test failed.") - - XCTAssert(t1 != t2, "Test failed.") - XCTAssert(t3 != t2, "Test failed.") - XCTAssert(t3 == (t1 + t2), "Test failed.") - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var s = RedBlackTree(uniqueKeys: true) + + XCTAssert(0 == s.count, "Test failed, got \(s.count).") + + for _ in 0..<1000 { + s.insert(value: 1, for: 1) + s.insert(value: 2, for: 2) + s.insert(value: 3, for: 3) + } + + XCTAssert(3 == s.count, "Test failed.\(s)") + XCTAssert(1 == s[0].value, "Test failed.") + XCTAssert(2 == s[1].value, "Test failed.") + XCTAssert(3 == s[2].value, "Test failed.") + + for _ in 0..<500 { + s.removeValue(for: 1) + s.removeValue(for: 3) + } + + XCTAssert(1 == s.count, "Test failed.") + s.removeValue(for: 2) + + XCTAssert(true == s.insert(value: 10, for: 2), "Test failed.") + XCTAssertEqual(1, s.count, "Test failed.") + XCTAssertEqual(10, s.findValue(for: 2), "Test failed.") + XCTAssertEqual(10, s[0].value, "Test failed.") + + s.removeValue(for: 2) + XCTAssertEqual(0, s.count, "Test failed.") + + s.insert(value: 1, for: 1) + s.insert(value: 2, for: 2) + s.insert(value: 3, for: 3) + + for i in s.startIndex..>(uniqueKeys: false) + s.insert(value: [1, 2, 3], for: "friends") + s["menu"] = [11, 22, 33] + + XCTAssert(s["friends"]! == s[0].value!, "Test failed.") + XCTAssert(s["menu"]! == s[1].value!, "Test failed.") + XCTAssert(s["empty"] == nil, "Test failed.") + s["menu"] = [22, 33, 44] + XCTAssert(s["menu"]! == [22, 33, 44], "Test failed.") + s["menu"] = nil + XCTAssert(2 == s.count, "Test failed.") + } + + func testValue() { + var t1 = RedBlackTree() + t1.insert(value: 1, for: 1) + t1.insert(value: 2, for: 2) + t1.insert(value: 3, for: 3) + + var t2 = RedBlackTree() + t2.insert(value: 4, for: 4) + t2.insert(value: 5, for: 5) + t2.insert(value: 6, for: 6) + + let t3 = t1 + t2 + + for i in 0..(uniqueKeys: true) + t1.insert(value: 1, for: 1) + t1.insert(value: 2, for: 2) + t1.insert(value: 3, for: 3) + t1.insert(value: 4, for: 4) + t1.insert(value: 5, for: 5) + t1.insert(value: 5, for: 5) + t1.insert(value: 6, for: 6) + + XCTAssert(0 == t1.index(of: 1), "Test failed.") + XCTAssert(5 == t1.index(of: 6), "Test failed.") + XCTAssert(-1 == t1.index(of: 100), "Test failed.") + } + + func testIndexOfNonUniqueKeys() { + var t1 = RedBlackTree() + t1.insert(value: 1, for: 1) + t1.insert(value: 2, for: 2) + t1.insert(value: 3, for: 3) + t1.insert(value: 4, for: 4) + t1.insert(value: 5, for: 5) + t1.insert(value: 5, for: 5) + t1.insert(value: 6, for: 6) + + XCTAssert(0 == t1.index(of: 1), "Test failed.") + XCTAssert(6 == t1.index(of: 6), "Test failed.") + XCTAssert(-1 == t1.index(of: 100), "Test failed.") + } + + func testOperands() { + var t1 = RedBlackTree(uniqueKeys: true) + t1.insert((1, 1), (2, 2), (3, 3), (4, 4)) + XCTAssertEqual(4, t1.count, "Test failed.") + + var t2 = RedBlackTree(uniqueKeys: true) + t2.insert((5, 5), (6, 6), (7, 7), (8, 8)) + XCTAssertEqual(4, t2.count, "Test failed.") + + let t3 = t1 + t2 + XCTAssertEqual(8, t3.count, "Test failed.") + + XCTAssert(t1 != t2, "Test failed.") + XCTAssert(t3 != t2, "Test failed.") + + XCTAssert(t3 == (t1 + t2), "Test failed.") + } + + func testPerformance() { + self.measure() {} + } } diff --git a/Tests/SortedDictionaryTests.swift b/Tests/SortedDictionaryTests.swift index 5003040..459337a 100644 --- a/Tests/SortedDictionaryTests.swift +++ b/Tests/SortedDictionaryTests.swift @@ -1,129 +1,157 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class SortedDictionaryTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let s: SortedDictionary = SortedDictionary() - - XCTAssert(0 == s.count, "Test failed, got \(s.count).") - - for _ in 0..<1000 { - s.insert((1, 1)) - s.insert((2, 2)) - s.insert((3, 3)) - } - - XCTAssert(3 == s.count, "Test failed.") - XCTAssert(1 == s[0].value, "Test failed.") - XCTAssert(2 == s[1].value, "Test failed.") - XCTAssert(3 == s[2].value, "Test failed.") - - for _ in 0..<500 { - s.removeValueForKeys(1) - s.removeValueForKeys(3) - } - - XCTAssert(1 == s.count, "Test failed.") - s.removeValueForKeys(2) - - s.insert((2, 10)) - XCTAssert(1 == s.count, "Test failed.") - XCTAssert(10 == s.findValueForKey(2), "Test failed.") - XCTAssert(10 == s[0].value!, "Test failed.") - - s.removeValueForKeys(2) - XCTAssert(0 == s.count, "Test failed.") - - s.insert((1, 1)) - s.insert((2, 2)) - s.insert((3, 3)) - s.insert((3, 3)) - s.updateValue(5, forKey: 3) - - let subs: SortedDictionary = s.search(3) - XCTAssert(1 == subs.count, "Test failed.") - - let generator: SortedDictionary.Generator = subs.generate() - while let x = generator.next() { - XCTAssert(5 == x.value, "Test failed.") - } - - for i in 0.. = SortedDictionary() - d1.insert(1, value: 1) - d1.insert(2, value: 2) - d1.insert(3, value: 3) - d1.insert(4, value: 4) - d1.insert(5, value: 5) - d1.insert(5, value: 5) - d1.insert(6, value: 6) - - XCTAssert(0 == d1.indexOf(1), "Test failed.") - XCTAssert(5 == d1.indexOf(6), "Test failed.") - XCTAssert(-1 == d1.indexOf(100), "Test failed.") - } - - func testKeys() { - let s: SortedDictionary = SortedDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) - let keys: SortedSet = SortedSet(elements: "adam", "daniel", "mike", "natalie") - XCTAssert(keys == s.keys, "Test failed.") - } - - func testValues() { - let s: SortedDictionary = SortedDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) - let values: Array = [1, 2, 3, 4] - XCTAssert(values == s.values, "Test failed.") - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var s = SortedDictionary() + + XCTAssert(0 == s.count, "Test failed, got \(s.count).") + + for _ in 0..<1000 { + s.insert((1, 1)) + s.insert((2, 2)) + s.insert((3, 3)) + } + + XCTAssert(3 == s.count, "Test failed.") + XCTAssert(1 == s[0].value, "Test failed.") + XCTAssert(2 == s[1].value, "Test failed.") + XCTAssert(3 == s[2].value, "Test failed.") + + for _ in 0..<500 { + s.removeValue(for: 1) + s.removeValue(for: 3) + } + + XCTAssert(1 == s.count, "Test failed.") + s.removeValue(for: 2) + + s.insert((2, 10)) + XCTAssert(1 == s.count, "Test failed.") + XCTAssert(10 == s.findValue(for: 2), "Test failed.") + XCTAssert(10 == s[0].value!, "Test failed.") + + s.removeValue(for: 2) + XCTAssert(0 == s.count, "Test failed.") + + s.insert((1, 1)) + s.insert((2, 2)) + s.insert((3, 3)) + s.insert((3, 3)) + s.update(value: 5, for: 3) + + let subs: SortedDictionary = s.search(for: 3) + XCTAssert(1 == subs.count, "Test failed.") + + let generator = subs.makeIterator() + while let x = generator.next() { + XCTAssert(5 == x.value, "Test failed.") + } + + for i in 0..() + d1.insert(value: 1, for: 1) + d1.insert(value: 2, for: 2) + d1.insert(value: 3, for: 3) + d1.insert(value: 4, for: 4) + d1.insert(value: 5, for: 5) + d1.insert(value: 5, for: 5) + d1.insert(value: 6, for: 6) + + XCTAssert(0 == d1.index(of: 1), "Test failed.") + XCTAssert(5 == d1.index(of: 6), "Test failed.") + XCTAssert(-1 == d1.index(of: 100), "Test failed.") + } + + func testKeys() { + let s = SortedDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) + XCTAssert(["adam", "daniel", "mike", "natalie"] == s.keys, "Test failed.") + } + + func testValues() { + let s = SortedDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) + let values = [1, 2, 3, 4] + XCTAssert(values == s.values, "Test failed.") + } + + func testLowerEntry() { + let s = SortedDictionary(elements: (1, 1), (2, 2), (3, 3), (5, 5), (8, 8), (13, 13), (21, 21), (34, 34)) + + XCTAssert(s.findLowerEntry(for: -15) == nil, "Test failed.") + XCTAssert(s.findLowerEntry(for: 0) == nil, "Test failed.") + XCTAssert(s.findLowerEntry(for: 1) == 1, "Test failed.") + XCTAssert(s.findLowerEntry(for: 2) == 2, "Test failed.") + XCTAssert(s.findLowerEntry(for: 3) == 3, "Test failed.") + XCTAssert(s.findLowerEntry(for: 4) == 3, "Test failed.") + XCTAssert(s.findLowerEntry(for: 5) == 5, "Test failed.") + XCTAssert(s.findLowerEntry(for: 6) == 5, "Test failed.") + XCTAssert(s.findLowerEntry(for: 7) == 5, "Test failed.") + XCTAssert(s.findLowerEntry(for: 8) == 8, "Test failed.") + XCTAssert(s.findLowerEntry(for: 9) == 8, "Test failed.") + XCTAssert(s.findLowerEntry(for: 10) == 8, "Test failed.") + XCTAssert(s.findLowerEntry(for: 40) == 34, "Test failed.") + XCTAssert(s.findLowerEntry(for: 50) == 34, "Test failed.") + } + + func testCeilingEntry() { + let s = SortedDictionary(elements: (1, 1), (2, 2), (3, 3), (5, 5), (8, 8), (13, 13), (21, 21), (34, 34)) + + XCTAssert(s.findCeilingEntry(for: -15) == 1, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 0) == 1, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 1) == 1, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 2) == 2, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 3) == 3, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 4) == 5, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 5) == 5, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 6) == 8, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 7) == 8, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 8) == 8, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 9) == 13, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 10) == 13, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 40) == nil, "Test failed.") + XCTAssert(s.findCeilingEntry(for: 50) == nil, "Test failed.") + } } diff --git a/Tests/SortedMultiDictionaryTests.swift b/Tests/SortedMultiDictionaryTests.swift index ce345c4..d286342 100644 --- a/Tests/SortedMultiDictionaryTests.swift +++ b/Tests/SortedMultiDictionaryTests.swift @@ -1,129 +1,124 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class SortedMultiDictionaryTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let s: SortedMultiDictionary = SortedMultiDictionary() - - XCTAssert(0 == s.count, "Test failed, got \(s.count).") - - for _ in 0..<1000 { - s.insert((1, 1)) - s.insert((2, 2)) - s.insert((3, 3)) - } - - XCTAssert(3000 == s.count, "Test failed.") - XCTAssert(1 == s[0].value, "Test failed.") - XCTAssert(1 == s[1].value, "Test failed.") - XCTAssert(1 == s[2].value, "Test failed.") - - for _ in 0..<500 { - s.removeValueForKeys(1) - s.removeValueForKeys(3) - } - - XCTAssert(1000 == s.count, "Test failed.") - s.removeValueForKeys(2) - - s.insert((2, 10)) - XCTAssert(1 == s.count, "Test failed.") - XCTAssert(10 == s.findValueForKey(2), "Test failed.") - XCTAssert(10 == s[0].value!, "Test failed.") - - s.removeValueForKeys(2) - XCTAssert(0 == s.count, "Test failed.") - - s.insert((1, 1)) - s.insert((2, 2)) - s.insert((3, 3)) - s.insert((3, 3)) - s.updateValue(5, forKey: 3) - - let subs: SortedMultiDictionary= s.search(3) - XCTAssert(2 == subs.count, "Test failed.") - - let generator: SortedMultiDictionary.Generator = subs.generate() - while let x = generator.next() { - XCTAssert(5 == x.value, "Test failed.") - } - - for i in 0.. = SortedMultiDictionary() - d1.insert(1, value: 1) - d1.insert(2, value: 2) - d1.insert(3, value: 3) - d1.insert(4, value: 4) - d1.insert(5, value: 5) - d1.insert(5, value: 5) - d1.insert(6, value: 6) - - XCTAssert(0 == d1.indexOf(1), "Test failed.") - XCTAssert(6 == d1.indexOf(6), "Test failed.") - XCTAssert(-1 == d1.indexOf(100), "Test failed.") - } - - func testKeys() { - let s: SortedMultiDictionary = SortedMultiDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) - let keys: SortedMultiSet = SortedMultiSet(elements: "adam", "daniel", "mike", "natalie") - XCTAssert(keys == s.keys, "Test failed.") - } - - func testValues() { - let s: SortedMultiDictionary = SortedMultiDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) - let values: Array = [1, 2, 3, 4] - XCTAssert(values == s.values, "Test failed.") - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var s = SortedMultiDictionary() + + XCTAssert(0 == s.count, "Test failed, got \(s.count).") + + for _ in 0..<1000 { + s.insert((1, 1)) + s.insert((2, 2)) + s.insert((3, 3)) + } + + XCTAssert(3000 == s.count, "Test failed.") + XCTAssert(1 == s[0].value, "Test failed.") + XCTAssert(1 == s[1].value, "Test failed.") + XCTAssert(1 == s[2].value, "Test failed.") + + for _ in 0..<500 { + s.removeValue(for: 1) + s.removeValue(for: 3) + } + + XCTAssert(1000 == s.count, "Test failed.") + s.removeValue(for: 2) + + s.insert((2, 10)) + XCTAssert(1 == s.count, "Test failed.") + XCTAssert(10 == s.findValue(for: 2), "Test failed.") + XCTAssert(10 == s[0].value!, "Test failed.") + + s.removeValue(for: 2) + XCTAssert(0 == s.count, "Test failed.") + + s.insert((1, 1)) + s.insert((2, 2)) + s.insert((3, 3)) + s.insert((3, 3)) + s.update(value: 5, for: 3) + + let subs = s.search(for: 3) + XCTAssert(2 == subs.count, "Test failed.") + + let generator = subs.makeIterator() + while let x = generator.next() { + XCTAssert(5 == x.value, "Test failed.") + } + + for i in 0..() + d1.insert(value: 1, for: 1) + d1.insert(value: 2, for: 2) + d1.insert(value: 3, for: 3) + d1.insert(value: 4, for: 4) + d1.insert(value: 5, for: 5) + d1.insert(value: 5, for: 5) + d1.insert(value: 6, for: 6) + + XCTAssert(0 == d1.index(of: 1), "Test failed.") + XCTAssert(6 == d1.index(of: 6), "Test failed.") + XCTAssert(-1 == d1.index(of: 100), "Test failed.") + } + + func testKeys() { + let s = SortedMultiDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) + let keys = SortedMultiSet(elements: "adam", "daniel", "mike", "natalie") + XCTAssert(keys.asArray == s.keys, "Test failed.") + } + + func testValues() { + let s = SortedMultiDictionary(elements: ("adam", 1), ("daniel", 2), ("mike", 3), ("natalie", 4)) + let values = [1, 2, 3, 4] + XCTAssert(values == s.values, "Test failed.") + } + + func testPerformance() { + self.measure() {} + } } diff --git a/Tests/SortedMultiSetTests.swift b/Tests/SortedMultiSetTests.swift index cb56c8e..0779292 100644 --- a/Tests/SortedMultiSetTests.swift +++ b/Tests/SortedMultiSetTests.swift @@ -1,242 +1,237 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class SortedMultiSetTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let s: SortedMultiSet = SortedMultiSet() - - XCTAssert(0 == s.count, "Test failed, got \(s.count).") - - for _ in 0..<1000 { - s.insert(1) - s.insert(2) - s.insert(3) - } - - XCTAssert(3000 == s.count, "Test failed.\(s)") - XCTAssert(1 == s[0], "Test failed.") - XCTAssert(2 == s[1000], "Test failed.") - XCTAssert(3 == s[2000], "Test failed.") - - for _ in 0..<500 { - s.remove(1) - s.remove(3) - } - - XCTAssert(1000 == s.count, "Test failed.") - s.remove(2) - s.remove(2) - s.insert(10) - XCTAssert(1 == s.count, "Test failed.") - - s.remove(10) - XCTAssert(0 == s.count, "Test failed.") - - s.insert(1) - s.insert(2) - s.insert(3) - - s.remove(1, 2) - XCTAssert(1 == s.count, "Test failed.") - - s.removeAll() - XCTAssert(0 == s.count, "Test failed.") - } - - func testRemove() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9) - s1.remove(1, 2, 3, 5) - XCTAssert(5 == s1.count, "Test failed.") - } - - func testIntersect() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 1, 2, 3, 4, 5, 5) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 1, 2, 5, 6, 7, 8, 9, 10) - let s3: SortedMultiSet = SortedMultiSet(elements: 1, 1, 2, 5, 5, 10, 11, 12, 13, 14, 15) - - XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5) == s1.intersect(s2), "Test failed. \(s1.intersect(s2))") - XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5, 5) == s1.intersect(s3), "Test failed. \(s1.intersect(s3))") - } - - func testIntersectInPlace() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 1, 2, 3, 4, 5) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 1, 2, 5, 6, 7, 8, 9, 10) - - s1.intersectInPlace(s2) - XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5) == s1, "Test failed. \(s1)") - - s1.insert(3, 4, 5, 5, 5) - s2.insert(5) - - s1.intersectInPlace(s2) - XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5, 5) == s1, "Test failed. \(s1)") - } - - func testIsDisjointWith() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3) - let s2: SortedMultiSet = SortedMultiSet(elements: 3, 4, 5) - let s3: SortedMultiSet = SortedMultiSet(elements: 5, 6, 7) - - XCTAssertFalse(s1.isDisjointWith(s2), "Test failed.") - XCTAssert(s1.isDisjointWith(s3), "Test failed.") - XCTAssertFalse(s2.isDisjointWith(s3), "Test failed.") - } - - func testSubtract() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 3, 3, 4, 5) - let s2: SortedMultiSet = SortedMultiSet(elements: 4, 5, -1) - let s3: SortedMultiSet = SortedMultiSet(elements: 3, 5, 0, -7) - - XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 3) == s1.subtract(s2), "Test failed. \(s1.subtract(s2))") - XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 4) == s1.subtract(s3), "Test failed. \(s1.subtract(s3))") - } - - func testSubtractInPlace() { - var s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 3, 3, 4, 5) - let s2: SortedMultiSet = SortedMultiSet(elements: 4, 5, -1) - let s3: SortedMultiSet = SortedMultiSet(elements: 3, 5, 0, -7) - - s1.subtractInPlace(s2) - XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 3) == s1, "Test failed. \(s1)") - s1 = SortedMultiSet(elements: 1, 2, 3, 3, 3, 4, 5) - s1.subtractInPlace(s3) - XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 4) == s1, "Test failed. \(s1)") - } - - func testUnion() { - let s1: SortedMultiSet = SortedMultiSet(elements: 0, 0, 1, 2, 3, 4, 7, 7, 5) - let s2: SortedMultiSet = SortedMultiSet(elements: 5, -1, 6, 8, 7, 9, 9) - - XCTAssert(SortedMultiSet(elements: -1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9) == s1.union(s2), "Test failed. \(s1.union(s2))") - } - - func testUnionInPlace() { - let s1: SortedMultiSet = SortedMultiSet(elements: 0, 0, 1, 2, 3, 4, 7, 7, 5) - let s2: SortedMultiSet = SortedMultiSet(elements: 5, -1, 0, 6, 8, 7, 9, 9) - - s1.unionInPlace(s2) - XCTAssert(SortedMultiSet(elements: -1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9) == s1, "Test failed. \(s1)") - } - - func testIsSubsetOf() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 2, 3) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5) - let s3: SortedMultiSet = SortedMultiSet(elements: 2, 2, 3, 4, 5) - - XCTAssert(s1 <= s1, "Test failed. \(s1.intersect(s2))") - XCTAssert(s1 <= s2, "Test failed.") - XCTAssertFalse(s1 <= s3, "Test failed.") - } - - func testIsSupersetOf() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 4, 5, 6, 7) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 4, 5) - let s3: SortedMultiSet = SortedMultiSet(elements: 5, 6, 7, 8) - - XCTAssert(s1 >= s1, "Test failed.") - XCTAssert(s1 >= s2, "Test failed.") - XCTAssertFalse(s1 >= s3, "Test failed.") - } - - func testIsStrictSubsetOf() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 4, 5) - let s3: SortedMultiSet = SortedMultiSet(elements: 2, 3, 4, 5) - - XCTAssert(s1 < s2, "Test failed.") - XCTAssertFalse(s1 < s3, "Test failed.") - } - - func testIsStrictSupersetOf() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 4, 5, 6, 7) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 4, 5) - let s3: SortedMultiSet = SortedMultiSet(elements: 5, 6, 7, 8) - - XCTAssert(s1 > s2, "Test failed.") - XCTAssertFalse(s1 > s3, "Test failed.") - } - - func testContains() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 4, 5, 6, 7) - XCTAssert(s1.contains(1, 2, 3), "Test failed.") - XCTAssertFalse(s1.contains(1, 2, 3, 10), "Test failed.") - } - - func testExclusiveOr() { - let s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5, 6, 7) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 3, 4, 5) - let s3: SortedMultiSet = SortedMultiSet(elements: 5, 6, 7, 8) - - XCTAssert(SortedMultiSet(elements: 6, 7) == s1.exclusiveOr(s2), "Test failed. \(s1.exclusiveOr(s2))") - XCTAssert(SortedMultiSet(elements: 1, 2, 2, 3, 4, 8) == s1.exclusiveOr(s3), "Test failed. \(s1.exclusiveOr(s3))") - XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 4, 6, 7, 8) == s2.exclusiveOr(s3), "Test failed.") - } - - func testExclusiveOrInPlace() { - var s1: SortedMultiSet = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5, 6, 7) - let s2: SortedMultiSet = SortedMultiSet(elements: 1, 2, 3, 4, 5) - let s3: SortedMultiSet = SortedMultiSet(elements: 5, 6, 7, 8) - - s1.exclusiveOrInPlace(s2) - XCTAssert(SortedMultiSet(elements: 6, 7) == s1, "Test failed.") - - s1 = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5, 6, 7) - s1.exclusiveOrInPlace(s3) - XCTAssert(SortedMultiSet(elements: 1, 2, 2, 3, 4, 8) == s1, "Test failed. \(s1)") - - s2.exclusiveOrInPlace(s3) - XCTAssert(SortedMultiSet(elements: 1, 2, 3, 4, 6, 7, 8) == s2, "Test failed. \(s2)") - } - - func testIndexOf() { - let s1: SortedMultiSet = SortedMultiSet() - s1.insert(1, 2, 3, 4, 5, 5, 6, 7) - - XCTAssert(0 == s1.indexOf(1), "Test failed.") - XCTAssert(6 == s1.indexOf(6), "Test failed.") - XCTAssert(-1 == s1.indexOf(100), "Test failed.") - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var s = SortedMultiSet() + + XCTAssert(0 == s.count, "Test failed, got \(s.count).") + + for _ in 0..<1000 { + s.insert(1) + s.insert(2) + s.insert(3) + } + + XCTAssert(3000 == s.count, "Test failed.\(s)") + XCTAssert(1 == s[0], "Test failed.") + XCTAssert(2 == s[1000], "Test failed.") + XCTAssert(3 == s[2000], "Test failed.") + + for _ in 0..<500 { + s.remove(1) + s.remove(3) + } + + XCTAssert(1000 == s.count, "Test failed.") + s.remove(2) + s.remove(2) + s.insert(10) + XCTAssert(1 == s.count, "Test failed.") + + s.remove(10) + XCTAssert(0 == s.count, "Test failed.") + + s.insert(1) + s.insert(2) + s.insert(3) + + s.remove(1, 2) + XCTAssert(1 == s.count, "Test failed.") + + s.removeAll() + XCTAssert(0 == s.count, "Test failed.") + } + + func testRemove() { + var s1 = SortedMultiSet(elements: 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9) + s1.remove(1, 2, 3, 5) + XCTAssert(5 == s1.count, "Test failed.") + } + + func testIntersect() { + let s1 = SortedMultiSet(elements: 1, 1, 2, 3, 4, 5, 5) + let s2 = SortedMultiSet(elements: 1, 1, 2, 5, 6, 7, 8, 9, 10) + let s3 = SortedMultiSet(elements: 1, 1, 2, 5, 5, 10, 11, 12, 13, 14, 15) + + XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5) == s1.intersection(s2), "Test failed. \(s1.intersection(s2))") + XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5, 5) == s1.intersection(s3), "Test failed. \(s1.intersection(s3))") + } + + func testIntersectInPlace() { + var s1 = SortedMultiSet(elements: 1, 1, 2, 3, 4, 5) + var s2 = SortedMultiSet(elements: 1, 1, 2, 5, 6, 7, 8, 9, 10) + + s1.formIntersection(s2) + XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5) == s1, "Test failed. \(s1)") + + s1.insert(3, 4, 5, 5, 5) + s2.insert(5) + + s1.formIntersection(s2) + XCTAssert(SortedMultiSet(elements: 1, 1, 2, 5, 5) == s1, "Test failed. \(s1)") + } + + func testIsDisjointWith() { + let s1 = SortedMultiSet(elements: 1, 2, 3) + let s2 = SortedMultiSet(elements: 3, 4, 5) + let s3 = SortedMultiSet(elements: 5, 6, 7) + + XCTAssertFalse(s1.isDisjoint(with: s2), "Test failed.") + XCTAssert(s1.isDisjoint(with: s3), "Test failed.") + XCTAssertFalse(s2.isDisjoint(with: s3), "Test failed.") + } + + func testSubtract() { + let s1 = SortedMultiSet(elements: 1, 2, 3, 3, 3, 4, 5) + let s2 = SortedMultiSet(elements: 4, 5, -1) + let s3 = SortedMultiSet(elements: 3, 5, 0, -7) + + XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 3) == s1.subtracting(s2), "Test failed. \(s1.subtracting(s2))") + XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 4) == s1.subtracting(s3), "Test failed. \(s1.subtracting(s3))") + } + + func testSubtractInPlace() { + var s1 = SortedMultiSet(elements: 1, 2, 3, 3, 3, 4, 5) + let s2 = SortedMultiSet(elements: 4, 5, -1) + let s3 = SortedMultiSet(elements: 3, 5, 0, -7) + + s1.subtract(s2) + XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 3) == s1, "Test failed. \(s1)") + s1 = SortedMultiSet(elements: 1, 2, 3, 3, 3, 4, 5) + s1.subtract(s3) + XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 4) == s1, "Test failed. \(s1)") + } + + func testUnion() { + let s1 = SortedMultiSet(elements: 0, 0, 1, 2, 3, 4, 7, 7, 5) + let s2 = SortedMultiSet(elements: 5, -1, 6, 8, 7, 9, 9) + + XCTAssert(SortedMultiSet(elements: -1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9) == s1.union(s2), "Test failed. \(s1.union(s2))") + } + + func testUnionInPlace() { + var s1 = SortedMultiSet(elements: 0, 0, 1, 2, 3, 4, 7, 7, 5) + let s2 = SortedMultiSet(elements: 5, -1, 0, 6, 8, 7, 9, 9) + + s1.formUnion(s2) + XCTAssert(SortedMultiSet(elements: -1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9) == s1, "Test failed. \(s1)") + } + + func testIsSubsetOf() { + let s1 = SortedMultiSet(elements: 1, 2, 2, 3) + let s2 = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5) + let s3 = SortedMultiSet(elements: 2, 2, 3, 4, 5) + + XCTAssert(s1 <= s1, "Test failed. \(s1.intersection(s2))") + XCTAssert(s1 <= s2, "Test failed.") + XCTAssertFalse(s1 <= s3, "Test failed.") + } + + func testIsSupersetOf() { + let s1 = SortedMultiSet(elements: 1, 2, 3, 4, 5, 6, 7) + let s2 = SortedMultiSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedMultiSet(elements: 5, 6, 7, 8) + + XCTAssert(s1 >= s1, "Test failed.") + XCTAssert(s1 >= s2, "Test failed.") + XCTAssertFalse(s1 >= s3, "Test failed.") + } + + func testIsStrictSubsetOf() { + let s1 = SortedMultiSet(elements: 1, 2, 3) + let s2 = SortedMultiSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedMultiSet(elements: 2, 3, 4, 5) + + XCTAssert(s1 < s2, "Test failed.") + XCTAssertFalse(s1 < s3, "Test failed.") + } + + func testIsStrictSupersetOf() { + let s1 = SortedMultiSet(elements: 1, 2, 3, 4, 5, 6, 7) + let s2 = SortedMultiSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedMultiSet(elements: 5, 6, 7, 8) + + XCTAssert(s1 > s2, "Test failed.") + XCTAssertFalse(s1 > s3, "Test failed.") + } + + func testContains() { + let s1 = SortedMultiSet(elements: 1, 2, 3, 4, 5, 6, 7) + XCTAssert(s1.contains(1, 2, 3), "Test failed.") + XCTAssertFalse(s1.contains(1, 2, 3, 10), "Test failed.") + } + + func testExclusiveOr() { + let s1 = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5, 6, 7) + let s2 = SortedMultiSet(elements: 1, 2, 3, 3, 4, 5) + let s3 = SortedMultiSet(elements: 5, 6, 7, 8) + + XCTAssert(SortedMultiSet(elements: 6, 7) == s1.symmetricDifference(s2), "Test failed. \(s1.symmetricDifference(s2))") + XCTAssert(SortedMultiSet(elements: 1, 2, 2, 3, 4, 8) == s1.symmetricDifference(s3), "Test failed. \(s1.symmetricDifference(s3))") + XCTAssert(SortedMultiSet(elements: 1, 2, 3, 3, 4, 6, 7, 8) == s2.symmetricDifference(s3), "Test failed.") + } + + func testExclusiveOrInPlace() { + var s1 = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5, 6, 7) + var s2 = SortedMultiSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedMultiSet(elements: 5, 6, 7, 8) + + s1.formSymmetricDifference(s2) + XCTAssert(SortedMultiSet(elements: 6, 7) == s1, "Test failed.") + + s1 = SortedMultiSet(elements: 1, 2, 2, 3, 4, 5, 6, 7) + s1.formSymmetricDifference(s3) + XCTAssert(SortedMultiSet(elements: 1, 2, 2, 3, 4, 8) == s1, "Test failed. \(s1)") + + s2.formSymmetricDifference(s3) + XCTAssert(SortedMultiSet(elements: 1, 2, 3, 4, 6, 7, 8) == s2, "Test failed. \(s2)") + } + + func testIndexOf() { + var s1 = SortedMultiSet() + s1.insert(1, 2, 3, 4, 5, 5, 6, 7) + + XCTAssert(0 == s1.index(of: 1), "Test failed.") + XCTAssert(6 == s1.index(of: 6), "Test failed.") + XCTAssert(-1 == s1.index(of: 100), "Test failed.") + } + + func testPerformance() { + self.measure() {} + } } diff --git a/Tests/SortedSetTest.swift b/Tests/SortedSetTest.swift index 19b49f0..649db1e 100644 --- a/Tests/SortedSetTest.swift +++ b/Tests/SortedSetTest.swift @@ -1,283 +1,278 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class SortedSetTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let s: SortedSet = SortedSet() - - XCTAssert(0 == s.count, "Test failed, got \(s.count).") - - for _ in 0..<1000 { - s.insert(1) - s.insert(2) - s.insert(3) - } - - XCTAssert(3 == s.count, "Test failed.\(s)") - XCTAssert(1 == s[0], "Test failed.") - XCTAssert(2 == s[1], "Test failed.") - XCTAssert(3 == s[2], "Test failed.") - - for _ in 0..<500 { - s.remove(1) - s.remove(3) - } - - XCTAssert(1 == s.count, "Test failed.") - - s.remove(2) - s.insert(10) - XCTAssert(1 == s.count, "Test failed.") - - s.remove(10) - XCTAssert(0 == s.count, "Test failed.") - - s.insert(1) - s.insert(2) - s.insert(3) - s.remove(1, 2) - XCTAssert(1 == s.count, "Test failed.") - - s.removeAll() - XCTAssert(0 == s.count, "Test failed.") - } - - func testRemove() { - let s1: SortedSet = SortedSet(elements: 22, 23, 1, 2, 3, 4, 5) - s1.remove(1, 2, 3) - XCTAssert(4 == s1.count, "Test failed.") - } - - func testIntersect() { - let s1: SortedSet = SortedSet(elements: 22, 23, 1, 2, 3, 4, 5) - let s2: SortedSet = SortedSet(elements: 22, 23, 5, 6, 7, 8, 9, 10) - - XCTAssert(SortedSet(elements: 22, 23, 5) == s1.intersect(s2), "Test failed. \(s1.intersect(s2))") - - XCTAssert(SortedSet() == s1.intersect(SortedSet()), "Test failed. \(s1)") - - let s3: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9) - let s4: SortedSet = SortedSet(elements: 11, 9, 7, 3, 8, 100, 99, 88, 77) - XCTAssert(SortedSet(elements: 9, 3, 7, 8) == s3.intersect(s4), "Test failed.") - } - - func testIntersectInPlace() { - let s1: SortedSet = SortedSet(elements: 22, 23, 1, 2, 3, 4, 5) - let s2: SortedSet = SortedSet(elements: 22, 23, 5, 6, 7, 8, 9, 10) - - s1.intersectInPlace(s2) - XCTAssert(SortedSet(elements: 22, 23, 5) == s1, "Test failed. \(s1)") - - s1.intersectInPlace(SortedSet()) - XCTAssert(SortedSet() == s1, "Test failed. \(s1)") - - let s3: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9) - let s4: SortedSet = SortedSet(elements: 11, 9, 7, 3, 8, 100, 99, 88, 77) - s3.intersectInPlace(s4) - XCTAssert(SortedSet(elements: 9, 3, 7, 8) == s3, "Test failed.") - } - - func testSubtract() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 7, 8, 9, 10) - let s2: SortedSet = SortedSet(elements: 4, 5, 6, 7) - - XCTAssert(SortedSet(elements: 1, 2, 3, 8, 9, 10) == s1.subtract(s2), "Test failed. \(s1.subtract(s2))") - - let s3: SortedSet = SortedSet(elements: 0, -1, -2, -7, 99, 100) - let s4: SortedSet = SortedSet(elements: -3, -5, -7, 99) - XCTAssert(SortedSet(elements: 0, -1, -2, 100) == s3.subtract(s4), "Test failed. \(s3.subtract(s4))") - } - - func testSubtractInPlace() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 7, 8, 9, 10) - let s2: SortedSet = SortedSet(elements: 4, 5, 6, 7) - - s1.subtractInPlace(s2) - XCTAssert(SortedSet(elements: 1, 2, 3, 8, 9, 10) == s1, "Test failed. \(s1)") - - let s3: SortedSet = SortedSet(elements: 0, -1, -2, -7, 99, 100) - let s4: SortedSet = SortedSet(elements: -3, -5, -7, 99) - s3.subtractInPlace(s4) - XCTAssert(SortedSet(elements: 0, -1, -2, 100) == s3, "Test failed. \(s3)") - } - - func testUnion() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s2: SortedSet = SortedSet(elements: 5, 6, 7, 8, 9) - let s3: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9) - - XCTAssert(s3 == s1.union(s2), "Test failed.") - } - - func testUnionInPlace() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s2: SortedSet = SortedSet(elements: 5, 6, 7, 8, 9) - let s3: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9) - - s1.unionInPlace(s2) - XCTAssert(s3 == s1, "Test failed.") - } - - func testExclusiveOr() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) - let s2: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s3: SortedSet = SortedSet(elements: 5, 6, 7, 8) - - XCTAssert(SortedSet(elements: 6, 7) == s1.exclusiveOr(s2), "Test failed. \(s1.exclusiveOr(s2))") - XCTAssert(SortedSet(elements: 1, 2, 3, 4, 8) == s1.exclusiveOr(s3), "Test failed.") - XCTAssert(SortedSet(elements: 1, 2, 3, 4, 6, 7, 8) == s2.exclusiveOr(s3), "Test failed.") - } - - func testExclusiveOrInPlace() { - var s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) - let s2: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s3: SortedSet = SortedSet(elements: 5, 6, 7, 8) - - s1.exclusiveOrInPlace(s2) - XCTAssert(SortedSet(elements: 6, 7) == s1, "Test failed. \(s1)") - - s1 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) - s1.exclusiveOrInPlace(s3) - XCTAssert(SortedSet(elements: 1, 2, 3, 4, 8) == s1, "Test failed. \(s1)") - - s2.exclusiveOrInPlace(s3) - XCTAssert(SortedSet(elements: 1, 2, 3, 4, 6, 7, 8) == s2, "Test failed. \(s2)") - } - - func testIsDisjointWith() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3) - let s2: SortedSet = SortedSet(elements: 3, 4, 5) - let s3: SortedSet = SortedSet(elements: 5, 6, 7) - - XCTAssertFalse(s1.isDisjointWith(s2), "Test failed. \(s1.isDisjointWith(s2))") - XCTAssert(s1.isDisjointWith(s3), "Test failed.") - XCTAssertFalse(s2.isDisjointWith(s3), "Test failed.") - } - - func testIsSubsetOf() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3) - let s2: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s3: SortedSet = SortedSet(elements: 2, 3, 4, 5) - - XCTAssert(s1 <= s1, "Test failed.") - XCTAssert(s1 <= s2, "Test failed.") - XCTAssertFalse(s1 <= s3, "Test failed.") - } - - func testIsSupersetOf() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) - let s2: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s3: SortedSet = SortedSet(elements: 5, 6, 7, 8) - - XCTAssert(s1 >= s1, "Test failed.") - XCTAssert(s1 >= s2, "Test failed.") - XCTAssertFalse(s1 >= s3, "Test failed.") - } - - func testIsStrictSubsetOf() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3) - let s2: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s3: SortedSet = SortedSet(elements: 2, 3, 4, 5) - - XCTAssert(s1 < s2, "Test failed.") - XCTAssertFalse(s1 < s3, "Test failed.") - } - - func testIsStrictSupersetOf() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) - let s2: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5) - let s3: SortedSet = SortedSet(elements: 5, 6, 7, 8) - - XCTAssert(s1 > s2, "Test failed.") - XCTAssertFalse(s1 > s3, "Test failed.") - } - - func testContains() { - let s1: SortedSet = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) - XCTAssert(s1.contains(1, 2, 3), "Test failed.") - XCTAssertFalse(s1.contains(1, 2, 3, 10), "Test failed.") - } - - func testIndexOf() { - let s1: SortedSet = SortedSet() - s1.insert(1, 2, 3, 4, 5, 6, 7) - - XCTAssert(0 == s1.indexOf(1), "Test failed.") - XCTAssert(5 == s1.indexOf(6), "Test failed.") - XCTAssert(-1 == s1.indexOf(100), "Test failed.") - } - - func testExample() { - let setA: SortedSet = SortedSet(elements: 1, 2, 3) // Sorted: [1, 2, 3] - let setB: SortedSet = SortedSet(elements: 4, 3, 6) // Sorted: [3, 4, 6] - - let setC: SortedSet = SortedSet(elements: 7, 1, 2) // Sorted: [1, 2, 7] - let setD: SortedSet = SortedSet(elements: 1, 7) // Sorted: [1, 7] - - let setE: SortedSet = SortedSet(elements: 1, 6, 7) // Sorted: [1, 6, 7] - - // Union. - print((setA + setB).count) // Output: 5 - print(setA.union(setB).count) // Output: 5 - - // Intersect. - print(setC.intersect(setD).count) // Output: 2 - - // Subset. - print(setD < setC) // true - print(setD.isSubsetOf(setC)) // true - - // Superset. - print(setD > setC) // false - print(setD.isSupersetOf(setC)) // false - - // Contains. - print(setE.contains(setA.first!)) // true - - // Probability. - print(setE.probabilityOf(setA.first!, setA.last!)) // 0.333333333333333 - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var s = SortedSet() + + XCTAssert(0 == s.count, "Test failed, got \(s.count).") + + for _ in 0..<1000 { + s.insert(1) + s.insert(2) + s.insert(3) + } + + XCTAssert(3 == s.count, "Test failed.\(s)") + XCTAssert(1 == s[0], "Test failed.") + XCTAssert(2 == s[1], "Test failed.") + XCTAssert(3 == s[2], "Test failed.") + + for _ in 0..<500 { + s.remove(1) + s.remove(3) + } + + XCTAssert(1 == s.count, "Test failed.") + + s.remove(2) + s.insert(10) + XCTAssert(1 == s.count, "Test failed.") + + s.remove(10) + XCTAssert(0 == s.count, "Test failed.") + + s.insert(1) + s.insert(2) + s.insert(3) + s.remove(1, 2) + XCTAssert(1 == s.count, "Test failed.") + + s.removeAll() + XCTAssert(0 == s.count, "Test failed.") + } + + func testRemove() { + var s1 = SortedSet(elements: 22, 23, 1, 2, 3, 4, 5) + s1.remove(1, 2, 3) + XCTAssert(4 == s1.count, "Test failed.") + } + + func testIntersect() { + let s1 = SortedSet(elements: 22, 23, 1, 2, 3, 4, 5) + let s2 = SortedSet(elements: 22, 23, 5, 6, 7, 8, 9, 10) + + XCTAssert(SortedSet(elements: 22, 23, 5) == s1.intersection(s2), "Test failed. \(s1.intersection(s2))") + + XCTAssert(SortedSet() == s1.intersection(SortedSet()), "Test failed. \(s1)") + + let s3 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9) + let s4 = SortedSet(elements: 11, 9, 7, 3, 8, 100, 99, 88, 77) + XCTAssert(SortedSet(elements: 9, 3, 7, 8) == s3.intersection(s4), "Test failed.") + } + + func testIntersectInPlace() { + var s1 = SortedSet(elements: 22, 23, 1, 2, 3, 4, 5) + let s2 = SortedSet(elements: 22, 23, 5, 6, 7, 8, 9, 10) + + s1.formIntersection(s2) + XCTAssert(SortedSet(elements: 22, 23, 5) == s1, "Test failed. \(s1)") + + s1.formIntersection(SortedSet()) + XCTAssert(SortedSet() == s1, "Test failed. \(s1)") + + var s3 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9) + let s4 = SortedSet(elements: 11, 9, 7, 3, 8, 100, 99, 88, 77) + s3.formIntersection(s4) + XCTAssert(SortedSet(elements: 9, 3, 7, 8) == s3, "Test failed.") + } + + func testSubtract() { + let s1 = SortedSet(elements: 1, 2, 3, 4, 5, 7, 8, 9, 10) + let s2 = SortedSet(elements: 4, 5, 6, 7) + + XCTAssert(SortedSet(elements: 1, 2, 3, 8, 9, 10) == s1.subtracting(s2), "Test failed. \(s1.subtracting(s2))") + + let s3 = SortedSet(elements: 0, -1, -2, -7, 99, 100) + let s4 = SortedSet(elements: -3, -5, -7, 99) + XCTAssert(SortedSet(elements: 0, -1, -2, 100) == s3.subtracting(s4), "Test failed. \(s3.subtracting(s4))") + } + + func testSubtractInPlace() { + var s1 = SortedSet(elements: 1, 2, 3, 4, 5, 7, 8, 9, 10) + let s2 = SortedSet(elements: 4, 5, 6, 7) + + s1.subtract(s2) + XCTAssert(SortedSet(elements: 1, 2, 3, 8, 9, 10) == s1, "Test failed. \(s1)") + + var s3 = SortedSet(elements: 0, -1, -2, -7, 99, 100) + let s4 = SortedSet(elements: -3, -5, -7, 99) + s3.subtract(s4) + XCTAssert(SortedSet(elements: 0, -1, -2, 100) == s3, "Test failed. \(s3)") + } + + func testUnion() { + let s1 = SortedSet(elements: 1, 2, 3, 4, 5) + let s2 = SortedSet(elements: 5, 6, 7, 8, 9) + let s3 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9) + + XCTAssert(s3 == s1.union(s2), "Test failed.") + } + + func testUnionInPlace() { + var s1 = SortedSet(elements: 1, 2, 3, 4, 5) + let s2 = SortedSet(elements: 5, 6, 7, 8, 9) + let s3 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7, 8, 9) + + s1.formUnion(s2) + XCTAssert(s3 == s1, "Test failed.") + } + + func testExclusiveOr() { + let s1 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) + let s2 = SortedSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedSet(elements: 5, 6, 7, 8) + + XCTAssert(SortedSet(elements: 6, 7) == s1.symmetricDifference(s2), "Test failed. \(s1.symmetricDifference(s2))") + XCTAssert(SortedSet(elements: 1, 2, 3, 4, 8) == s1.symmetricDifference(s3), "Test failed.") + XCTAssert(SortedSet(elements: 1, 2, 3, 4, 6, 7, 8) == s2.symmetricDifference(s3), "Test failed.") + } + + func testExclusiveOrInPlace() { + var s1 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) + var s2 = SortedSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedSet(elements: 5, 6, 7, 8) + + s1.formSymmetricDifference(s2) + XCTAssert(SortedSet(elements: 6, 7) == s1, "Test failed. \(s1)") + + s1 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) + s1.formSymmetricDifference(s3) + XCTAssert(SortedSet(elements: 1, 2, 3, 4, 8) == s1, "Test failed. \(s1)") + + s2.formSymmetricDifference(s3) + XCTAssert(SortedSet(elements: 1, 2, 3, 4, 6, 7, 8) == s2, "Test failed. \(s2)") + } + + func testIsDisjointWith() { + let s1 = SortedSet(elements: 1, 2, 3) + let s2 = SortedSet(elements: 3, 4, 5) + let s3 = SortedSet(elements: 5, 6, 7) + + XCTAssertFalse(s1.isDisjoint(with: s2), "Test failed. \(s1.isDisjoint(with: s2))") + XCTAssert(s1.isDisjoint(with: s3), "Test failed.") + XCTAssertFalse(s2.isDisjoint(with: s3), "Test failed.") + } + + func testIsSubsetOf() { + let s1 = SortedSet(elements: 1, 2, 3) + let s2 = SortedSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedSet(elements: 2, 3, 4, 5) + + XCTAssert(s1 <= s1, "Test failed.") + XCTAssert(s1 <= s2, "Test failed.") + XCTAssertFalse(s1 <= s3, "Test failed.") + } + + func testIsSupersetOf() { + let s1 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) + let s2 = SortedSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedSet(elements: 5, 6, 7, 8) + + XCTAssert(s1 >= s1, "Test failed.") + XCTAssert(s1 >= s2, "Test failed.") + XCTAssertFalse(s1 >= s3, "Test failed.") + } + + func testIsStrictSubsetOf() { + let s1 = SortedSet(elements: 1, 2, 3) + let s2 = SortedSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedSet(elements: 2, 3, 4, 5) + + XCTAssert(s1 < s2, "Test failed.") + XCTAssertFalse(s1 < s3, "Test failed.") + } + + func testIsStrictSupersetOf() { + let s1 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) + let s2 = SortedSet(elements: 1, 2, 3, 4, 5) + let s3 = SortedSet(elements: 5, 6, 7, 8) + + XCTAssert(s1 > s2, "Test failed.") + XCTAssertFalse(s1 > s3, "Test failed.") + } + + func testContains() { + let s1 = SortedSet(elements: 1, 2, 3, 4, 5, 6, 7) + XCTAssert(s1.contains(1, 2, 3), "Test failed.") + XCTAssertFalse(s1.contains(1, 2, 3, 10), "Test failed.") + } + + func testIndexOf() { + var s1 = SortedSet() + s1.insert(1, 2, 3, 4, 5, 6, 7) + + XCTAssert(0 == s1.index(of: 1), "Test failed.") + XCTAssert(5 == s1.index(of: 6), "Test failed.") + XCTAssert(-1 == s1.index(of: 100), "Test failed.") + } + + func testExample() { + let setA = SortedSet(elements: 1, 2, 3) // Sorted: [1, 2, 3] + let setB = SortedSet(elements: 4, 3, 6) // Sorted: [3, 4, 6] + + let setC = SortedSet(elements: 7, 1, 2) // Sorted: [1, 2, 7] + let setD = SortedSet(elements: 1, 7) // Sorted: [1, 7] + + let setE = SortedSet(elements: 1, 6, 7) // Sorted: [1, 6, 7] + + // Union. + print((setA + setB).count) // Output: 5 + print(setA.union(setB).count) // Output: 5 + + // Intersect. + print(setC.intersection(setD).count) // Output: 2 + + // Subset. + print(setD < setC) // true + print(setD.isSubset(of: setC)) // true + + // Superset. + print(setD > setC) // false + print(setD.isSuperset(of: setC)) // false + + // Contains. + print(setE.contains(setA.first!)) // true + + // Probability. + print(setE.probability(of: setA.first!, setA.last!)) // 0.333333333333333 + } + + func testPerformance() { + self.measure() {} + } } diff --git a/Tests/StackTests.swift b/Tests/StackTests.swift index d746f43..68536ce 100644 --- a/Tests/StackTests.swift +++ b/Tests/StackTests.swift @@ -1,94 +1,89 @@ /* -* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* * Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of Algorithm nor the names of its -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* 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. -*/ + * The MIT License (MIT) + * + * Copyright (C) 2019, CosmicMind, Inc. . + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ import XCTest @testable import Algorithm class StackTests: XCTestCase { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - } - - func testInt() { - let s: Stack = Stack() - - s.push(1) - s.push(2) - s.push(3) - - XCTAssert(3 == s.count, "Count incorrect, got \(s.count).") - XCTAssert(3 == s.top, "Top incorrect, got \(s.top)") - - s.push(5) - s.push(6) - s.push(7) - - XCTAssert(6 == s.count, "Count incorrect, got \(s.count).") - XCTAssert(7 == s.top, "Top incorrect, got \(s.top)") - - XCTAssert(7 == s.pop() && 5 == s.count && 6 == s.top, "Pop incorrect") - XCTAssert(6 == s.pop() && 4 == s.count && 5 == s.top, "Pop incorrect") - XCTAssert(5 == s.pop() && 3 == s.count && 3 == s.top, "Pop incorrect") - XCTAssert(3 == s.pop() && 2 == s.count && 2 == s.top, "Pop incorrect") - XCTAssert(2 == s.pop() && 1 == s.count && 1 == s.top, "Pop incorrect") - XCTAssert(1 == s.pop() && 0 == s.count && nil == s.top, "Pop incorrect") - - s.push(1) - s.push(2) - s.push(3) - s.removeAll() - - XCTAssert(0 == s.count, "Count incorrect, got \(s.count).") - } - - func testConcat() { - let s1: Stack = Stack() - s1.push(1) - s1.push(2) - s1.push(3) - - let s2: Stack = Stack() - s2.push(4) - s2.push(5) - s2.push(6) - - let s3: Stack = s1 + s2 - XCTAssert(6 == s3.count, "Concat incorrect.") - } - - func testPerformance() { - self.measureBlock() {} - } + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInt() { + var s = Stack() + + s.push(1) + s.push(2) + s.push(3) + + XCTAssert(3 == s.count, "Count incorrect, got \(s.count).") + XCTAssert(3 == s.top, "Top incorrect, got \(String(describing: s.top))") + + s.push(5) + s.push(6) + s.push(7) + + XCTAssert(6 == s.count, "Count incorrect, got \(s.count).") + XCTAssert(7 == s.top, "Top incorrect, got \(String(describing: s.top))") + + XCTAssert(7 == s.pop() && 5 == s.count && 6 == s.top, "Pop incorrect") + XCTAssert(6 == s.pop() && 4 == s.count && 5 == s.top, "Pop incorrect") + XCTAssert(5 == s.pop() && 3 == s.count && 3 == s.top, "Pop incorrect") + XCTAssert(3 == s.pop() && 2 == s.count && 2 == s.top, "Pop incorrect") + XCTAssert(2 == s.pop() && 1 == s.count && 1 == s.top, "Pop incorrect") + XCTAssert(1 == s.pop() && 0 == s.count && nil == s.top, "Pop incorrect") + + s.push(1) + s.push(2) + s.push(3) + s.removeAll() + + XCTAssert(0 == s.count, "Count incorrect, got \(s.count).") + } + + func testConcat() { + var s1 = Stack() + s1.push(1) + s1.push(2) + s1.push(3) + + var s2 = Stack() + s2.push(4) + s2.push(5) + s2.push(6) + + let s3 = s1 + s2 + XCTAssert(6 == s3.count, "Concat incorrect.") + } + + func testPerformance() { + self.measure() {} + } }