Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| acb62df760 | |||
| f303e02f63 | |||
| 244d0128c9 | |||
| 0d5e16fc4f | |||
| ecd3f176e5 | |||
| ac3f8fa5eb | |||
| 19046fb4a8 | |||
| 005ef5c3ee | |||
| 68f2557694 | |||
| 72d4779e9b | |||
| 8547583792 | |||
| 3688348461 | |||
| f875439709 | |||
| 1920f07525 | |||
| 69ed90dcfc | |||
| 33fa9622ce | |||
| 468ad1c83a | |||
| 174c21d58f | |||
| 5f076fccbb | |||
| 642b5623b7 | |||
| 03b5817530 | |||
| 7ba07fcef1 | |||
| 0e1273e2ab | |||
| 7b8b3c39a3 | |||
| 1e5c2926a7 | |||
| b678702e3d | |||
| 4e4b205dcb | |||
| b345a3e8df | |||
| 2cf9220874 | |||
| 08e9ff5371 | |||
| e7adba0cb9 | |||
| 5a288f4197 | |||
| 56bfdfc953 | |||
| 34efc031a4 | |||
| 3541842cd3 | |||
| d75fe1429b | |||
| f8d5a75dd5 | |||
| 596a7d2c1b | |||
| f2a320bc6b | |||
| f36353d61f | |||
| fb30ee0cc3 | |||
| 4234d43565 | |||
| 77d0b4937a | |||
| 4c89d79979 | |||
| 397e3e4c20 | |||
| a4abc2ee8b | |||
| 2e54a9935b | |||
| ea47632047 | |||
| 1d9696939a | |||
| 1a26252cf7 | |||
| 0d73c529f2 | |||
| 42030fb42a | |||
| e689725b4d | |||
| b896bb0751 | |||
| 37bfcd67b2 | |||
| cb7638e658 | |||
| 95e5cc9c11 | |||
| 917cb33775 | |||
| 0b061bb25d | |||
| 1d439a86ed | |||
| be3d9f1c69 | |||
| f89f30b9d1 |
@@ -27,3 +27,6 @@ DerivedData
|
||||
|
||||
# Carthage
|
||||
Carthage
|
||||
|
||||
# SPM
|
||||
.build
|
||||
|
||||
+24
-9
@@ -5,7 +5,7 @@ branches:
|
||||
|
||||
# OS
|
||||
os: osx
|
||||
language: objective-c
|
||||
language: swift
|
||||
|
||||
# Xcode Project
|
||||
xcode_project: OrderedDictionary.xcodeproj
|
||||
@@ -13,31 +13,46 @@ xcode_project: OrderedDictionary.xcodeproj
|
||||
# Build Matrix
|
||||
matrix:
|
||||
include:
|
||||
# Swift 4.0 / macOS
|
||||
- osx_image: xcode9.2
|
||||
# Swift 5.0.1 / macOS
|
||||
- osx_image: xcode10.2
|
||||
xcode_scheme: OrderedDictionary-Mac
|
||||
env:
|
||||
- XCODE_SDK=macosx
|
||||
- XCODE_ACTION="build test"
|
||||
- XCODE_DESTINATION="arch=x86_64"
|
||||
- XCODE_PLAYGROUND_TARGET="x86_64-apple-macosx10.10"
|
||||
# Swift 4.0 / iOS
|
||||
- osx_image: xcode9.2
|
||||
# Swift 5.0.1 / iOS
|
||||
- osx_image: xcode10.2
|
||||
xcode_scheme: OrderedDictionary-iOS
|
||||
env:
|
||||
- XCODE_SDK=iphonesimulator
|
||||
- XCODE_ACTION="build-for-testing test-without-building"
|
||||
- XCODE_DESTINATION="platform=iOS Simulator,name=iPhone 6s,OS=10.1"
|
||||
# Swift 4.1 / macOS
|
||||
- osx_image: xcode9.3beta
|
||||
# Swift 4.1.2 / macOS
|
||||
- osx_image: xcode9.4
|
||||
xcode_scheme: OrderedDictionary-Mac
|
||||
env:
|
||||
- XCODE_SDK=macosx
|
||||
- XCODE_ACTION="build test"
|
||||
- XCODE_DESTINATION="arch=x86_64"
|
||||
- XCODE_PLAYGROUND_TARGET="x86_64-apple-macosx10.10"
|
||||
# Swift 4.1 / iOS
|
||||
- osx_image: xcode9.3beta
|
||||
# Swift 4.1.2 / iOS
|
||||
- osx_image: xcode9.4
|
||||
xcode_scheme: OrderedDictionary-iOS
|
||||
env:
|
||||
- XCODE_SDK=iphonesimulator
|
||||
- XCODE_ACTION="build-for-testing test-without-building"
|
||||
- XCODE_DESTINATION="platform=iOS Simulator,name=iPhone 6s,OS=10.1"
|
||||
# Swift 4.0.3 / macOS
|
||||
- osx_image: xcode9.2
|
||||
xcode_scheme: OrderedDictionary-Mac
|
||||
env:
|
||||
- XCODE_SDK=macosx
|
||||
- XCODE_ACTION="build test"
|
||||
- XCODE_DESTINATION="arch=x86_64"
|
||||
- XCODE_PLAYGROUND_TARGET="x86_64-apple-macosx10.10"
|
||||
# Swift 4.0.3 / iOS
|
||||
- osx_image: xcode9.2
|
||||
xcode_scheme: OrderedDictionary-iOS
|
||||
env:
|
||||
- XCODE_SDK=iphonesimulator
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 Lukas Kubanek
|
||||
Copyright © 2015-2020 Lukas Kubanek
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8048C8AB22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */; };
|
||||
8048C8AC22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */; };
|
||||
8055B0421E201C5D009DC3EE /* OrderedDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8055B0381E201C5D009DC3EE /* OrderedDictionary.framework */; };
|
||||
8055B0551E201D24009DC3EE /* OrderedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 8055B0531E201D24009DC3EE /* OrderedDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8055B0591E201DF3009DC3EE /* OrderedDictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8055B0581E201DF3009DC3EE /* OrderedDictionaryTests.swift */; };
|
||||
80A203A11F3F483700622481 /* OrderedDictionary+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80A203A01F3F483700622481 /* OrderedDictionary+Codable.swift */; };
|
||||
80A203A21F3F4C1F00622481 /* OrderedDictionary+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80A203A01F3F483700622481 /* OrderedDictionary+Codable.swift */; };
|
||||
80B28EA01E201EC9007E3A77 /* OrderedDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80B28E971E201EC8007E3A77 /* OrderedDictionary.framework */; };
|
||||
80B28EAE1E201F15007E3A77 /* OrderedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 8055B0531E201D24009DC3EE /* OrderedDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
80B28EB01E201F1C007E3A77 /* OrderedDictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8055B0581E201DF3009DC3EE /* OrderedDictionaryTests.swift */; };
|
||||
80E8E21D1E20301E00395E49 /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E8E21C1E20301E00395E49 /* OrderedDictionary.swift */; };
|
||||
80E8E21F1E20425B00395E49 /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E8E21C1E20301E00395E49 /* OrderedDictionary.swift */; };
|
||||
@@ -39,11 +39,13 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
8024947E2277123600AB44C7 /* Package@swift-4.2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Package@swift-4.2.swift"; sourceTree = "<group>"; };
|
||||
8024947F2277136D00AB44C7 /* Package@swift-5.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Package@swift-5.swift"; sourceTree = "<group>"; };
|
||||
804879371E217C7700AD31A3 /* build.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build.sh; sourceTree = "<group>"; };
|
||||
804879381E217CA100AD31A3 /* validate-playgrounds.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "validate-playgrounds.sh"; sourceTree = "<group>"; };
|
||||
8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrderedDictionary+Deprecated.swift"; sourceTree = "<group>"; };
|
||||
8055B0381E201C5D009DC3EE /* OrderedDictionary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OrderedDictionary.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8055B0411E201C5D009DC3EE /* OrderedDictionary_Mac_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OrderedDictionary_Mac_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8055B0531E201D24009DC3EE /* OrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OrderedDictionary.h; sourceTree = "<group>"; };
|
||||
8055B0581E201DF3009DC3EE /* OrderedDictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderedDictionaryTests.swift; sourceTree = "<group>"; };
|
||||
807AA68F1F1E587A00576474 /* OrderedDictionary+Codable.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "OrderedDictionary+Codable.playground"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
80A203A01F3F483700622481 /* OrderedDictionary+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrderedDictionary+Codable.swift"; sourceTree = "<group>"; };
|
||||
@@ -52,6 +54,9 @@
|
||||
80B28EB41E201F81007E3A77 /* Info-Tests.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-Tests.plist"; sourceTree = "<group>"; };
|
||||
80B28EB51E201F81007E3A77 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
80B28EB71E2020DD007E3A77 /* OrderedDictionary.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = OrderedDictionary.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
80DE329220F4CAFA0053EDA7 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
|
||||
80DE329320F4DD910053EDA7 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
80DE329420F4DD910053EDA7 /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = "<group>"; };
|
||||
80E8E21C1E20301E00395E49 /* OrderedDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderedDictionary.swift; sourceTree = "<group>"; };
|
||||
80E8E22F1E2133D100395E49 /* OrderedDictionary+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OrderedDictionary+Description.swift"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -102,6 +107,11 @@
|
||||
8055B02E1E201C5D009DC3EE = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
80DE329320F4DD910053EDA7 /* README.md */,
|
||||
80DE329420F4DD910053EDA7 /* LICENSE.md */,
|
||||
80DE329220F4CAFA0053EDA7 /* Package.swift */,
|
||||
8024947E2277123600AB44C7 /* Package@swift-4.2.swift */,
|
||||
8024947F2277136D00AB44C7 /* Package@swift-5.swift */,
|
||||
8055B0521E201D24009DC3EE /* Sources */,
|
||||
80B28EB11E201F72007E3A77 /* Playgrounds */,
|
||||
8055B0571E201DF3009DC3EE /* Tests */,
|
||||
@@ -125,10 +135,10 @@
|
||||
8055B0521E201D24009DC3EE /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8055B0531E201D24009DC3EE /* OrderedDictionary.h */,
|
||||
80E8E21C1E20301E00395E49 /* OrderedDictionary.swift */,
|
||||
80A203A01F3F483700622481 /* OrderedDictionary+Codable.swift */,
|
||||
80E8E22F1E2133D100395E49 /* OrderedDictionary+Description.swift */,
|
||||
8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
@@ -166,7 +176,6 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8055B0551E201D24009DC3EE /* OrderedDictionary.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -174,7 +183,6 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
80B28EAE1E201F15007E3A77 /* OrderedDictionary.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -260,37 +268,38 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0820;
|
||||
LastUpgradeCheck = 0930;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = "Lukas Kubanek";
|
||||
TargetAttributes = {
|
||||
8055B0371E201C5D009DC3EE = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
8055B0401E201C5D009DC3EE = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
80B28E961E201EC8007E3A77 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
80B28E9E1E201EC9007E3A77 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 8055B0321E201C5D009DC3EE /* Build configuration list for PBXProject "OrderedDictionary" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 8055B02E1E201C5D009DC3EE;
|
||||
productRefGroup = 8055B0391E201C5D009DC3EE /* Products */;
|
||||
@@ -341,6 +350,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8048C8AB22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */,
|
||||
80E8E2301E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */,
|
||||
80E8E21D1E20301E00395E49 /* OrderedDictionary.swift in Sources */,
|
||||
80A203A11F3F483700622481 /* OrderedDictionary+Codable.swift in Sources */,
|
||||
@@ -359,6 +369,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8048C8AC22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */,
|
||||
80E8E2311E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */,
|
||||
80E8E21F1E20425B00395E49 /* OrderedDictionary.swift in Sources */,
|
||||
80A203A21F3F4C1F00622481 /* OrderedDictionary+Codable.swift in Sources */,
|
||||
@@ -393,6 +404,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -446,6 +458,7 @@
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
@@ -455,6 +468,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -500,6 +514,7 @@
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
@@ -508,6 +523,7 @@
|
||||
8055B04D1E201C5D009DC3EE /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
@@ -522,13 +538,13 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionary;
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
8055B04E1E201C5D009DC3EE /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
@@ -543,7 +559,6 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionary;
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -556,7 +571,6 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionaryTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -569,13 +583,13 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionaryTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
80B28EA91E201EC9007E3A77 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
@@ -590,7 +604,6 @@
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -598,6 +611,7 @@
|
||||
80B28EAA1E201EC9007E3A77 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
@@ -612,7 +626,6 @@
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
@@ -627,7 +640,6 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.lukaskubanek.OrderedDictionary-iOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -640,7 +652,6 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.lukaskubanek.OrderedDictionary-iOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_VERSION = 4.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1120"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,6 +27,15 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-Mac"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -39,17 +48,6 @@
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-Mac"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -70,8 +68,6 @@
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1120"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,6 +27,15 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-iOS"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -39,17 +48,6 @@
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-iOS"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -70,8 +68,6 @@
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// swift-tools-version:4
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "OrderedDictionary",
|
||||
products: [
|
||||
.library(
|
||||
name: "OrderedDictionary",
|
||||
targets: ["OrderedDictionary"]
|
||||
)
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(
|
||||
name: "OrderedDictionary",
|
||||
dependencies: [],
|
||||
path: "Sources"
|
||||
),
|
||||
.testTarget(
|
||||
name: "OrderedDictionaryTests",
|
||||
dependencies: ["OrderedDictionary"],
|
||||
path: "Tests"
|
||||
)
|
||||
],
|
||||
swiftLanguageVersions: [4]
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
// swift-tools-version:4.2
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "OrderedDictionary",
|
||||
products: [
|
||||
.library(
|
||||
name: "OrderedDictionary",
|
||||
targets: ["OrderedDictionary"]
|
||||
)
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(
|
||||
name: "OrderedDictionary",
|
||||
dependencies: [],
|
||||
path: "Sources"
|
||||
),
|
||||
.testTarget(
|
||||
name: "OrderedDictionaryTests",
|
||||
dependencies: ["OrderedDictionary"],
|
||||
path: "Tests"
|
||||
)
|
||||
],
|
||||
swiftLanguageVersions: [.v4, .v4_2]
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
// swift-tools-version:5.0
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "OrderedDictionary",
|
||||
products: [
|
||||
.library(
|
||||
name: "OrderedDictionary",
|
||||
targets: ["OrderedDictionary"]
|
||||
)
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(
|
||||
name: "OrderedDictionary",
|
||||
dependencies: [],
|
||||
path: "Sources"
|
||||
),
|
||||
.testTarget(
|
||||
name: "OrderedDictionaryTests",
|
||||
dependencies: ["OrderedDictionary"],
|
||||
path: "Tests"
|
||||
)
|
||||
],
|
||||
swiftLanguageVersions: [.v5]
|
||||
)
|
||||
@@ -31,19 +31,3 @@ let plistDecoder = PropertyListDecoder()
|
||||
let orderedDictionary3 = try! plistDecoder.decode(OrderedDictionary<String, Int>.self, from: plistData)
|
||||
|
||||
orderedDictionary1 == orderedDictionary3
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Non-codable Type
|
||||
// ======================================================= //
|
||||
|
||||
struct NonCodableType {
|
||||
var string: String
|
||||
}
|
||||
|
||||
let orderedDictionary4: OrderedDictionary<String, NonCodableType> = [
|
||||
"A" : NonCodableType(string: "Foo"),
|
||||
"B" : NonCodableType(string: "Bar"),
|
||||
"C" : NonCodableType(string: "Baz")
|
||||
]
|
||||
|
||||
//try? jsonEncoder.encode(x)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# OrderedDictionary
|
||||
|
||||
[](https://travis-ci.org/lukaskubanek/OrderedDictionary) [](https://github.com/lukaskubanek/OrderedDictionary/releases) [](https://developer.apple.com/swift/ "Swift 4")  [](https://github.com/Carthage/Carthage) [](LICENSE.md)
|
||||
[](https://travis-ci.org/lukaskubanek/OrderedDictionary) [](https://github.com/lukaskubanek/OrderedDictionary/releases) [](https://developer.apple.com/swift/ "Swift 4.0+")  [](https://github.com/Carthage/Carthage)
|
||||
[](https://github.com/Carthage/Carthage) [](LICENSE.md)
|
||||
|
||||
**OrderedDictionary** is a lightweight implementation of an ordered dictionary data structure in Swift.
|
||||
|
||||
@@ -12,27 +13,39 @@ Internally, `OrderedDictionary` uses a backing store composed of an instance of
|
||||
|
||||
## Requirements
|
||||
|
||||
- Swift 4.0+
|
||||
- Swift 4.0+ (4.0, 4.2, 5.0, 5.1)
|
||||
- Xcode 9.2+
|
||||
- iOS 8.0+ / macOS 10.10+
|
||||
|
||||
## Installation
|
||||
|
||||
This library is distributed as a Swift framework and can be integrated into your project in following ways:
|
||||
The library is distributed as a Swift framework and can be integrated into your project in following ways:
|
||||
|
||||
### Carthage
|
||||
#### Carthage
|
||||
|
||||
The easiest way is to use the package manager [Carthage](https://github.com/Carthage/Carthage).
|
||||
If you use [Carthage](https://github.com/Carthage/Carthage) for managing your dependencies, put OrderedDictionary into your `Cartfile`:
|
||||
|
||||
1. Add `github "lukaskubanek/OrderedDictionary"` to your `Cartfile`.
|
||||
2. Run `carthage bootstrap`.
|
||||
3. Drag either the `OrderedDictionary.xcodeproj` or the `OrderedDictionary.framework` into your project/workspace and link your target against the `OrderedDictionary.framework`.
|
||||
4. Make sure the framework [gets copied](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application) to your application bundle.
|
||||
5. Import the framework using `import OrderedDictionary`.
|
||||
```plain
|
||||
github "lukaskubanek/OrderedDictionary"
|
||||
```
|
||||
|
||||
### Submodule & Xcode Project
|
||||
Then, drag either the `OrderedDictionary.xcodeproj` or the `OrderedDictionary.framework` into your project/workspace and link your target against the `OrderedDictionary.framework`. Also make sure that the framework [gets copied](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application) to your application bundle.
|
||||
|
||||
Another option is to use [Git submodules](http://git-scm.com/book/en/v2/Git-Tools-Submodules) and integrating the Xcode project `OrderedDictionary.xcodeproj` directly to your Xcode workspace.
|
||||
#### Swift Package Manager
|
||||
|
||||
Another option is to use the [Swift Package Manager](https://swift.org/package-manager/). If you prefer this option, put OrderedDictionary as a dependency to your `Package.swift`:
|
||||
|
||||
```plain
|
||||
.package(url: "https://github.com/lukaskubanek/OrderedDictionary.git", from: "2.4.0")
|
||||
```
|
||||
|
||||
#### Git Submodules
|
||||
|
||||
Yet another option is using [Git submodules](http://git-scm.com/book/en/v2/Git-Tools-Submodules) and integrating the Xcode project `OrderedDictionary.xcodeproj` from the submodule directly to your Xcode workspace.
|
||||
|
||||
#### ⚠️ Note About CocoaPods
|
||||
|
||||
Although there is high demand for [CocoaPods](https://cocoapods.org) support, this method won't be officially supported by this library. Since I'm not using CocoaPods myself and since I think this method will be once replaced by the Swift Package Manager, I don't want to put any effort in maintaining an official podspec. If you really want to include this library via CocoaPods, there is still a way by creating a custom podspec (see the last section of [this post](https://guides.cocoapods.org/syntax/podfile.html#pod)).
|
||||
|
||||
## Usage & Docs
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ if [[ -z $XCODE_DESTINATION ]]; then
|
||||
fi
|
||||
|
||||
set -o pipefail
|
||||
|
||||
swift --version
|
||||
|
||||
xcodebuild $XCODE_ACTION \
|
||||
-project "$TRAVIS_XCODE_PROJECT" \
|
||||
-scheme "$TRAVIS_XCODE_SCHEME" \
|
||||
|
||||
@@ -120,9 +120,11 @@ extension OrderedDictionary: Decodable {
|
||||
|
||||
#endif
|
||||
|
||||
fileprivate extension DecodingError {
|
||||
extension DecodingError {
|
||||
|
||||
fileprivate static func unkeyedContainerReachedEndBeforeValue(_ codingPath: [CodingKey]) -> DecodingError {
|
||||
fileprivate static func unkeyedContainerReachedEndBeforeValue(
|
||||
_ codingPath: [CodingKey]
|
||||
) -> DecodingError {
|
||||
return DecodingError.dataCorrupted(
|
||||
DecodingError.Context(
|
||||
codingPath: codingPath,
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
extension OrderedDictionary {
|
||||
|
||||
@available(*, deprecated, message: "Please use init(values:uniquelyKeyedBy:).", renamed: "init(values:uniquelyKeyedBy:)")
|
||||
public init<S: Sequence>(
|
||||
values: S,
|
||||
keyedBy extractKey: (Value) -> Key
|
||||
) where S.Element == Value {
|
||||
#if swift(>=4.1.3)
|
||||
self.init(values: values, uniquelyKeyedBy: extractKey)
|
||||
#else
|
||||
try! self.init(values: values, uniquelyKeyedBy: extractKey)
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Please use init(values:uniquelyKeyedBy:).", renamed: "init(values:uniquelyKeyedBy:)")
|
||||
public init(
|
||||
values: [Value],
|
||||
keyedBy keyPath: KeyPath<Value, Key>
|
||||
) {
|
||||
self.init(values: values, uniquelyKeyedBy: keyPath)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Please use init(uniqueKeysWithValues:).", renamed: "init(uniqueKeysWithValues:)")
|
||||
public init<S: Sequence>(_ elements: S) where S.Element == Element {
|
||||
self.init(uniqueKeysWithValues: elements)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ extension OrderedDictionary {
|
||||
|
||||
fileprivate func makeDescription(debug: Bool) -> String {
|
||||
// The implementation of the description is inspired by zwaldowski's implementation of the
|
||||
// ordered dictionary. See http://bit.ly/2iqGhrb
|
||||
// ordered dictionary. See https://bit.ly/2RiWfJu
|
||||
|
||||
if isEmpty { return "[:]" }
|
||||
|
||||
|
||||
+242
-79
@@ -27,48 +27,87 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
// MARK: - Initialization
|
||||
// ======================================================= //
|
||||
|
||||
/// Creates an empty ordered dictionary.
|
||||
public init() {}
|
||||
|
||||
/// Creates an ordered dictionary from a sequence of values keyed by a key which gets extracted
|
||||
/// from the value in the provided closure.
|
||||
///
|
||||
/// - Parameter values: The sequence of values.
|
||||
/// - Parameter getKey: The closure which provides a key for the given value from the values
|
||||
/// sequence.
|
||||
public init<Values: Sequence>(values: Values, keyedBy getKey: (Value) -> Key) where Values.Element == Value {
|
||||
self.init(values.map { (getKey($0), $0) })
|
||||
/// Initializes an empty ordered dictionary.
|
||||
public init() {
|
||||
self._orderedKeys = [Key]()
|
||||
self._keysToValues = [Key: Value]()
|
||||
}
|
||||
|
||||
/// Creates an ordered dictionary from a sequence of values keyed by a key loaded from the value
|
||||
/// at the given key path.
|
||||
///
|
||||
/// - Parameter values: The sequence of values.
|
||||
/// - Parameter keyPath: The key path for the value to locate its key at.
|
||||
public init(values: [Value], keyedBy keyPath: KeyPath<Value, Key>) {
|
||||
self.init(values.map { ($0[keyPath: keyPath], $0) })
|
||||
/// Initializes an empty ordered dictionary with preallocated space for at least the specified
|
||||
/// number of elements.
|
||||
public init(minimumCapacity: Int) {
|
||||
self.init()
|
||||
self.reserveCapacity(minimumCapacity)
|
||||
}
|
||||
|
||||
/// Creates an ordered dictionary from a regular unsorted dictionary by sorting it using the
|
||||
/// Initializes an ordered dictionary from a regular unsorted dictionary by sorting it using
|
||||
/// the given sort function.
|
||||
///
|
||||
/// - Parameter unsorted: The unsorted dictionary.
|
||||
/// - Parameter areInIncreasingOrder: The sort function which compares the key-value pairs.
|
||||
public init(unsorted: Dictionary<Key, Value>, areInIncreasingOrder: (Element, Element) -> Bool) {
|
||||
let elements = unsorted
|
||||
.map { (key: $0.key, value: $0.value) }
|
||||
.sorted(by: areInIncreasingOrder)
|
||||
public init(
|
||||
unsorted: Dictionary<Key, Value>,
|
||||
areInIncreasingOrder: (Element, Element) throws -> Bool
|
||||
) rethrows {
|
||||
let keysAndValues = try Array(unsorted).sorted(by: areInIncreasingOrder)
|
||||
|
||||
self.init(elements)
|
||||
self.init(
|
||||
uniqueKeysWithValues: keysAndValues,
|
||||
minimumCapacity: unsorted.count
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates an ordered dictionary from a sequence of key-value pairs.
|
||||
/// Initializes an ordered dictionary from a sequence of values keyed by a unique key extracted
|
||||
/// from the value using the given closure.
|
||||
///
|
||||
/// - Parameter elements: The key-value pairs that will make up the new ordered dictionary.
|
||||
/// Each key in `elements` must be unique.
|
||||
public init<S: Sequence>(_ elements: S) where S.Element == Element {
|
||||
for (key, value) in elements {
|
||||
precondition(!containsKey(key), "Elements sequence contains duplicate keys")
|
||||
/// - Parameter values: The sequence of values.
|
||||
/// - Parameter extractKey: The closure which extracts a key from the value. The returned keys
|
||||
/// must be unique for all values from the sequence.
|
||||
public init<S: Sequence>(
|
||||
values: S,
|
||||
uniquelyKeyedBy extractKey: (Value) throws -> Key
|
||||
) rethrows where S.Element == Value {
|
||||
self.init(uniqueKeysWithValues: try values.map { value in
|
||||
return (try extractKey(value), value)
|
||||
})
|
||||
}
|
||||
|
||||
/// Initializes an ordered dictionary from a sequence of values keyed by a unique key extracted
|
||||
/// from the value using the given key path.
|
||||
///
|
||||
/// - Parameter values: The sequence of values.
|
||||
/// - Parameter keyPath: The key path to use for extracting a key from the value. The extracted
|
||||
/// keys must be unique for all values from the sequence.
|
||||
public init<S: Sequence>(
|
||||
values: S,
|
||||
uniquelyKeyedBy keyPath: KeyPath<Value, Key>
|
||||
) where S.Element == Value {
|
||||
self.init(uniqueKeysWithValues: values.map { value in
|
||||
return (value[keyPath: keyPath], value)
|
||||
})
|
||||
}
|
||||
|
||||
/// Initializes an ordered dictionary from a sequence of key-value pairs.
|
||||
///
|
||||
/// - Parameter keysAndValues: A sequence of key-value pairs to use for the new ordered
|
||||
/// dictionary. Every key in `keysAndValues` must be unique.
|
||||
public init<S: Sequence>(
|
||||
uniqueKeysWithValues keysAndValues: S
|
||||
) where S.Element == Element {
|
||||
self.init(
|
||||
uniqueKeysWithValues: keysAndValues,
|
||||
minimumCapacity: keysAndValues.underestimatedCount
|
||||
)
|
||||
}
|
||||
|
||||
private init<S: Sequence>(
|
||||
uniqueKeysWithValues keysAndValues: S,
|
||||
minimumCapacity: Int
|
||||
) where S.Element == Element {
|
||||
self.init(minimumCapacity: minimumCapacity)
|
||||
|
||||
for (key, value) in keysAndValues {
|
||||
precondition(!containsKey(key), "Sequence of key-value pairs contains duplicate keys")
|
||||
self[key] = value
|
||||
}
|
||||
}
|
||||
@@ -96,6 +135,49 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
return _keysToValues
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Indices
|
||||
// ======================================================= //
|
||||
|
||||
/// The indices that are valid for subscripting the ordered dictionary.
|
||||
public var indices: Indices {
|
||||
return _orderedKeys.indices
|
||||
}
|
||||
|
||||
/// The position of the first key-value pair in a non-empty ordered dictionary.
|
||||
public var startIndex: Index {
|
||||
return _orderedKeys.startIndex
|
||||
}
|
||||
|
||||
/// The position which is one greater than the position of the last valid key-value pair in the
|
||||
/// ordered dictionary.
|
||||
public var endIndex: Index {
|
||||
return _orderedKeys.endIndex
|
||||
}
|
||||
|
||||
/// Returns the position immediately after the given index.
|
||||
public func index(after i: Index) -> Index {
|
||||
return _orderedKeys.index(after: i)
|
||||
}
|
||||
|
||||
/// Returns the position immediately before the given index.
|
||||
public func index(before i: Index) -> Index {
|
||||
return _orderedKeys.index(before: i)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Slices
|
||||
// ======================================================= //
|
||||
|
||||
/// Accesses a contiguous subrange of the ordered dictionary.
|
||||
///
|
||||
/// - Parameter bounds: A range of the ordered dictionary's indices. The bounds of the range
|
||||
/// must be valid indices of the ordered dictionary.
|
||||
/// - Returns: The slice view at the ordered dictionary in the specified subrange.
|
||||
public subscript(bounds: Range<Index>) -> SubSequence {
|
||||
return OrderedDictionarySlice(base: self, bounds: bounds)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Key-based Access
|
||||
// ======================================================= //
|
||||
@@ -134,7 +216,7 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
/// - Parameter key: The key to be looked up.
|
||||
/// - Returns: `true` if the ordered dictionary contains the given key; otherwise, `false`.
|
||||
public func containsKey(_ key: Key) -> Bool {
|
||||
return _orderedKeys.contains(key)
|
||||
return _keysToValues[key] != nil
|
||||
}
|
||||
|
||||
/// Returns the value associated with the given key if the key is found in the ordered
|
||||
@@ -151,13 +233,13 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
/// key-value pair if the key does not exist.
|
||||
///
|
||||
/// - Parameter value: The new value to add to the ordered dictionary.
|
||||
/// - Parameter key: The key to associate with `value`. If `key` already exists in the ordered
|
||||
/// - Parameter key: The key to associate with `value`. If `key` already exists in the ordered
|
||||
/// dictionary, `value` replaces the existing associated value. If `key` is not already a key
|
||||
/// of the ordered dictionary, the `(key, value)` pair is appended at the end of the ordered
|
||||
/// dictionary.
|
||||
@discardableResult
|
||||
public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? {
|
||||
if _orderedKeys.contains(key) {
|
||||
if containsKey(key) {
|
||||
let currentValue = _unsafeValue(forKey: key)
|
||||
|
||||
_keysToValues[key] = value
|
||||
@@ -239,7 +321,11 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
/// - Returns: The index for `key` and its associated value if `key` is in the ordered
|
||||
/// dictionary; otherwise, `nil`.
|
||||
public func index(forKey key: Key) -> Index? {
|
||||
#if swift(>=5.0)
|
||||
return _orderedKeys.firstIndex(of: key)
|
||||
#else
|
||||
return _orderedKeys.index(of: key)
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns the key-value pair at the specified index, or `nil` if there is no key-value pair
|
||||
@@ -385,7 +471,11 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
return element
|
||||
}
|
||||
|
||||
private func _canUpdate(_ newElement: Element, at index: Index, keyPresentAtIndex: inout Bool) -> Bool {
|
||||
private func _canUpdate(
|
||||
_ newElement: Element,
|
||||
at index: Index,
|
||||
keyPresentAtIndex: inout Bool
|
||||
) -> Bool {
|
||||
precondition(indices.contains(index), "OrderedDictionary index is out of range")
|
||||
|
||||
let currentIndexOfKey = self.index(forKey: newElement.key)
|
||||
@@ -396,6 +486,34 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
return keyNotPresent || keyPresentAtIndex
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Removing First & Last Elements
|
||||
// ======================================================= //
|
||||
|
||||
/// Removes and returns the first key-value pair of the ordered dictionary if it is not empty.
|
||||
public mutating func popFirst() -> Element? {
|
||||
guard !isEmpty else { return nil }
|
||||
return remove(at: startIndex)
|
||||
}
|
||||
|
||||
/// Removes and returns the last key-value pair of the ordered dictionary if it is not empty.
|
||||
public mutating func popLast() -> Element? {
|
||||
guard !isEmpty else { return nil }
|
||||
return remove(at: index(before: endIndex))
|
||||
}
|
||||
|
||||
/// Removes and returns the first key-value pair of the ordered dictionary.
|
||||
public mutating func removeFirst() -> Element {
|
||||
precondition(!isEmpty, "Cannot remove key-value pairs from empty OrderedDictionary")
|
||||
return remove(at: startIndex)!
|
||||
}
|
||||
|
||||
/// Removes and returns the last key-value pair of the ordered dictionary.
|
||||
public mutating func removeLast() -> Element {
|
||||
precondition(!isEmpty, "Cannot remove key-value pairs from empty OrderedDictionary")
|
||||
return remove(at: index(before: endIndex))!
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Moving Elements
|
||||
// ======================================================= //
|
||||
@@ -442,8 +560,10 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
/// should be ordered before its second argument; otherwise, `false`.
|
||||
///
|
||||
/// - SeeAlso: MutableCollection.sort(by:), sorted(by:)
|
||||
public mutating func sort(by areInIncreasingOrder: (Element, Element) -> Bool) {
|
||||
_orderedKeys = _sortedElements(by: areInIncreasingOrder).map { $0.key }
|
||||
public mutating func sort(
|
||||
by areInIncreasingOrder: (Element, Element) throws -> Bool
|
||||
) rethrows {
|
||||
_orderedKeys = try _sortedElements(by: areInIncreasingOrder).map { $0.key }
|
||||
}
|
||||
|
||||
/// Returns a new ordered dictionary, sorted using the given predicate as the comparison between
|
||||
@@ -457,55 +577,74 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
///
|
||||
/// - SeeAlso: MutableCollection.sorted(by:), sort(by:)
|
||||
/// - MutatingVariant: sort
|
||||
public func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> OrderedDictionary<Key, Value> {
|
||||
return OrderedDictionary(_sortedElements(by: areInIncreasingOrder))
|
||||
public func sorted(
|
||||
by areInIncreasingOrder: (Element, Element) throws -> Bool
|
||||
) rethrows -> OrderedDictionary<Key, Value> {
|
||||
return OrderedDictionary(uniqueKeysWithValues: try _sortedElements(by: areInIncreasingOrder))
|
||||
}
|
||||
|
||||
private func _sortedElements(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element] {
|
||||
return sorted(by: areInIncreasingOrder)
|
||||
private func _sortedElements(
|
||||
by areInIncreasingOrder: (Element, Element) throws -> Bool
|
||||
) rethrows -> [Element] {
|
||||
return try sorted(by: areInIncreasingOrder)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Slices
|
||||
// MARK: - Mapping Values
|
||||
// ======================================================= //
|
||||
|
||||
/// Accesses a contiguous subrange of the ordered dictionary.
|
||||
///
|
||||
/// - Parameter bounds: A range of the ordered dictionary's indices. The bounds of the range
|
||||
/// must be valid indices of the ordered dictionary.
|
||||
/// - Returns: The slice view at the ordered dictionary in the specified subrange.
|
||||
public subscript(bounds: Range<Index>) -> SubSequence {
|
||||
return OrderedDictionarySlice(base: self, bounds: bounds)
|
||||
/// Returns a new ordered dictionary containing the keys of this ordered dictionary with the
|
||||
/// values transformed by the given closure by preserving the original order.
|
||||
public func mapValues<T>(
|
||||
_ transform: (Value) throws -> T
|
||||
) rethrows -> OrderedDictionary<Key, T> {
|
||||
var result = OrderedDictionary<Key, T>()
|
||||
|
||||
for (key, value) in self {
|
||||
result[key] = try transform(value)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/// Returns a new ordered dictionary containing only the key-value pairs that have non-nil
|
||||
/// values as the result of transformation by the given closure by preserving the original
|
||||
/// order.
|
||||
public func compactMapValues<T>(
|
||||
_ transform: (Value) throws -> T?
|
||||
) rethrows -> OrderedDictionary<Key, T> {
|
||||
var result = OrderedDictionary<Key, T>()
|
||||
|
||||
for (key, value) in self {
|
||||
if let transformedValue = try transform(value) {
|
||||
result[key] = transformedValue
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Indices
|
||||
// MARK: - Capacity
|
||||
// ======================================================= //
|
||||
|
||||
/// The indices that are valid for subscripting the ordered dictionary.
|
||||
public var indices: Indices {
|
||||
return _orderedKeys.indices
|
||||
|
||||
/// The total number of elements that the ordered dictionary can contain without allocating
|
||||
/// new storage.
|
||||
public var capacity: Int {
|
||||
return Swift.min(_orderedKeys.capacity, _keysToValues.capacity)
|
||||
}
|
||||
|
||||
/// The position of the first key-value pair in a non-empty ordered dictionary.
|
||||
public var startIndex: Index {
|
||||
return _orderedKeys.startIndex
|
||||
}
|
||||
|
||||
/// The position which is one greater than the position of the last valid key-value pair in the
|
||||
/// ordered dictionary.
|
||||
public var endIndex: Index {
|
||||
return _orderedKeys.endIndex
|
||||
}
|
||||
|
||||
/// Returns the position immediately after the given index.
|
||||
public func index(after i: Index) -> Index {
|
||||
return _orderedKeys.index(after: i)
|
||||
}
|
||||
|
||||
/// Returns the position immediately before the given index.
|
||||
public func index(before i: Index) -> Index {
|
||||
return _orderedKeys.index(before: i)
|
||||
/// Reserves enough space to store the specified number of elements, when appropriate
|
||||
/// for the underlying types.
|
||||
///
|
||||
/// If you are adding a known number of elements to an ordered dictionary, use this method
|
||||
/// to avoid multiple reallocations. This method ensures that the underlying types of the
|
||||
/// ordered dictionary have space allocated for at least the requested number of elements.
|
||||
///
|
||||
/// - Parameter minimumCapacity: The requested number of elements to store.
|
||||
public mutating func reserveCapacity(_ minimumCapacity: Int) {
|
||||
_orderedKeys.reserveCapacity(minimumCapacity)
|
||||
_keysToValues.reserveCapacity(minimumCapacity)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -513,10 +652,10 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
// ======================================================= //
|
||||
|
||||
/// The backing storage for the ordered keys.
|
||||
fileprivate var _orderedKeys = [Key]()
|
||||
fileprivate var _orderedKeys: [Key]
|
||||
|
||||
/// The backing storage for the mapping of keys to values.
|
||||
fileprivate var _keysToValues = [Key: Value]()
|
||||
fileprivate var _keysToValues: [Key: Value]
|
||||
|
||||
}
|
||||
|
||||
@@ -568,19 +707,20 @@ public typealias OrderedDictionaryValues<Key: Hashable, Value> = LazyMapBidirect
|
||||
|
||||
extension OrderedDictionary: ExpressibleByArrayLiteral {
|
||||
|
||||
/// Creates an ordered dictionary initialized from an array literal containing a list of
|
||||
/// key-value pairs.
|
||||
/// Initializes an ordered dictionary initialized from an array literal containing a list of
|
||||
/// key-value pairs. Every key in `elements` must be unique.
|
||||
public init(arrayLiteral elements: Element...) {
|
||||
self.init(elements)
|
||||
self.init(uniqueKeysWithValues: elements)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OrderedDictionary: ExpressibleByDictionaryLiteral {
|
||||
|
||||
/// Creates an ordered dictionary initialized from a dictionary literal.
|
||||
/// Initializes an ordered dictionary initialized from a dictionary literal. Every key in
|
||||
/// `elements` must be unique.
|
||||
public init(dictionaryLiteral elements: (Key, Value)...) {
|
||||
self.init(elements.map { element in
|
||||
self.init(uniqueKeysWithValues: elements.map { element in
|
||||
let (key, value) = element
|
||||
return (key: key, value: value)
|
||||
})
|
||||
@@ -608,3 +748,26 @@ extension OrderedDictionary where Value: Equatable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Dictionary Extension
|
||||
// ======================================================= //
|
||||
|
||||
extension Dictionary {
|
||||
|
||||
/// Returns an ordered dictionary containing the key-value pairs from the dictionary, sorted
|
||||
/// using the given sort function.
|
||||
///
|
||||
/// - Parameter areInIncreasingOrder: The sort function which compares the key-value pairs.
|
||||
/// - Returns: The ordered dictionary.
|
||||
/// - SeeAlso: OrderedDictionary.init(unsorted:areInIncreasingOrder:)
|
||||
public func sorted(
|
||||
by areInIncreasingOrder: (Element, Element) throws -> Bool
|
||||
) rethrows -> OrderedDictionary<Key, Value> {
|
||||
return try OrderedDictionary(
|
||||
unsorted: self,
|
||||
areInIncreasingOrder: areInIncreasingOrder
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.0</string>
|
||||
<string>2.4.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2015-2018 Lukas Kubanek. All rights reserved.</string>
|
||||
<string>Copyright © 2015-2020 Lukas Kubanek. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
|
||||
@@ -2,8 +2,7 @@ import OrderedDictionary
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
#if swift(>=4.1)
|
||||
#else
|
||||
#if !swift(>=4.1)
|
||||
|
||||
/// This is a shim for testing the equality in Swift <4.1.
|
||||
public func XCTAssertEqual<K, V: Equatable>(
|
||||
@@ -20,7 +19,7 @@ public func XCTAssertEqual<K, V: Equatable>(
|
||||
line: line
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
struct TestValue: Equatable {
|
||||
@@ -37,76 +36,112 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
// ======================================================= //
|
||||
|
||||
func testInitializationUsingArrayLiteral() {
|
||||
let expected = OrderedDictionary<String, Int>([
|
||||
let actual: OrderedDictionary<String, Int> = [
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("C", 3)
|
||||
]
|
||||
|
||||
let expected = OrderedDictionary<String, Int>(uniqueKeysWithValues: [
|
||||
(key: "A", value: 1),
|
||||
(key: "B", value: 2),
|
||||
(key: "C", value: 3)
|
||||
])
|
||||
let actual: OrderedDictionary<String, Int> = [("A", 1), ("B", 2), ("C", 3)]
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testInitializationUsingDictionaryLiteral() {
|
||||
let expected = OrderedDictionary<String, Int>([
|
||||
let actual: OrderedDictionary<String, Int> = [
|
||||
"A": 1,
|
||||
"B": 2,
|
||||
"C": 3
|
||||
]
|
||||
|
||||
let expected = OrderedDictionary<String, Int>(uniqueKeysWithValues: [
|
||||
(key: "A", value: 1),
|
||||
(key: "B", value: 2),
|
||||
(key: "C", value: 3)
|
||||
])
|
||||
let actual: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testInitializationUsingValuesAndKeyProviderClosure() {
|
||||
let values = [1, 2, 3]
|
||||
let actual = OrderedDictionary(
|
||||
values: [1, 2, 3],
|
||||
uniquelyKeyedBy: { "\($0)" }
|
||||
)
|
||||
|
||||
let expected = OrderedDictionary<String, Int>([
|
||||
let expected = OrderedDictionary<String, Int>(uniqueKeysWithValues: [
|
||||
(key: "1", value: 1),
|
||||
(key: "2", value: 2),
|
||||
(key: "3", value: 3)
|
||||
])
|
||||
let actual = OrderedDictionary(values: values, keyedBy: { "\($0)" })
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testInitializationUsingValuesAnyKeyPath() {
|
||||
let values = [
|
||||
TestValue(string: "A"),
|
||||
TestValue(string: "B"),
|
||||
TestValue(string: "C")
|
||||
]
|
||||
let actual = OrderedDictionary(
|
||||
values: [
|
||||
TestValue(string: "A"),
|
||||
TestValue(string: "B"),
|
||||
TestValue(string: "C")
|
||||
],
|
||||
uniquelyKeyedBy: \.string
|
||||
)
|
||||
|
||||
let expected = OrderedDictionary<String, TestValue>([
|
||||
let expected = OrderedDictionary<String, TestValue>(uniqueKeysWithValues: [
|
||||
(key: "A", value: TestValue(string: "A")),
|
||||
(key: "B", value: TestValue(string: "B")),
|
||||
(key: "C", value: TestValue(string: "C"))
|
||||
])
|
||||
let actual = OrderedDictionary(values: values, keyedBy: \.string)
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testInitializationUsingUnsortedDictionaryAndSortFunction() {
|
||||
let unsorted = [
|
||||
2: "foo",
|
||||
1: "bar",
|
||||
4: "baz",
|
||||
5: "bat",
|
||||
3: "bam"
|
||||
]
|
||||
let actual = OrderedDictionary(
|
||||
unsorted: [
|
||||
2: "foo",
|
||||
1: "bar",
|
||||
4: "baz",
|
||||
5: "bat",
|
||||
3: "bam"
|
||||
],
|
||||
areInIncreasingOrder: { $0.key < $1.key }
|
||||
)
|
||||
|
||||
let expected = OrderedDictionary([
|
||||
let expected = OrderedDictionary(uniqueKeysWithValues: [
|
||||
(key: 1, value: "bar"),
|
||||
(key: 2, value: "foo"),
|
||||
(key: 3, value: "bam"),
|
||||
(key: 4, value: "baz"),
|
||||
(key: 5, value: "bat")
|
||||
])
|
||||
let actual = OrderedDictionary(unsorted: unsorted, areInIncreasingOrder: { $0.key < $1.key })
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testCreationFromDictionary() {
|
||||
let actual = [
|
||||
2: "foo",
|
||||
1: "bar",
|
||||
4: "baz",
|
||||
5: "bat",
|
||||
3: "bam"
|
||||
].sorted(by: { $0.key < $1.key })
|
||||
|
||||
let expected = OrderedDictionary(uniqueKeysWithValues: [
|
||||
(key: 1, value: "bar"),
|
||||
(key: 2, value: "foo"),
|
||||
(key: 3, value: "bam"),
|
||||
(key: 4, value: "baz"),
|
||||
(key: 5, value: "bat")
|
||||
])
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -148,8 +183,8 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
let index = indexesIterator.next()
|
||||
let (expectedKey, expectedValue) = orderedDictionary[index!]
|
||||
|
||||
XCTAssertEqual(expectedKey, actualKey)
|
||||
XCTAssertEqual(expectedValue, actualValue)
|
||||
XCTAssertEqual(actualKey, expectedKey)
|
||||
XCTAssertEqual(actualValue, expectedValue)
|
||||
}
|
||||
|
||||
XCTAssertNil(iterator.next())
|
||||
@@ -158,29 +193,29 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
|
||||
func testAccessingOrderedKeys() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
let expected = ["A", "B", "C"]
|
||||
let actual = Array(orderedDictionary.orderedKeys)
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = ["A", "B", "C"]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testAccessingOrderedValues() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
let expected = [1, 2, 3]
|
||||
let actual = Array(orderedDictionary.orderedValues)
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = [1, 2, 3]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testAccessingUnsortedDictionary() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
let expected = ["A": 1, "B": 2, "C": 3]
|
||||
let actual = orderedDictionary.unorderedDictionary
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -223,11 +258,11 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
orderedDictionary.insert((key: "U", value: 16), at: 2)
|
||||
orderedDictionary.insert((key: "V", value: 17), at: 5)
|
||||
orderedDictionary.insert((key: "W", value: 18), at: 2)
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["T": 15, "A": 1, "W": 18, "U": 16, "B": 2, "C": 3, "V": 17]
|
||||
let actual = orderedDictionary
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected: OrderedDictionary<String, Int> = ["T": 15, "A": 1, "W": 18, "U": 16, "B": 2, "C": 3, "V": 17]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionWithDuplicateKey() {
|
||||
@@ -262,10 +297,10 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
XCTAssertTrue(previousElement! == ("B", 2))
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "D": 4, "C": 3]
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "D": 4, "C": 3]
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testIndexBasedUpdateMethodByReplacingSameKey() {
|
||||
@@ -275,10 +310,10 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
XCTAssertTrue(previousElement! == ("B", 2))
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "B": 42, "C": 3]
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "B": 42, "C": 3]
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testIndexBasedUpdateMethodByDuplicatingKey() {
|
||||
@@ -332,26 +367,100 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
func testIndexBasedRemoval() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let (expectedKey1, expectedValue1) = ("A", 1)
|
||||
let (actualKey1, actualValue1) = orderedDictionary.remove(at: 0)!
|
||||
let (expectedKey1, expectedValue1) = ("A", 1)
|
||||
|
||||
XCTAssertEqual(expectedKey1, actualKey1)
|
||||
XCTAssertEqual(expectedValue1, actualValue1)
|
||||
XCTAssertEqual(actualKey1, expectedKey1)
|
||||
XCTAssertEqual(actualValue1, expectedValue1)
|
||||
|
||||
let (expectedKey2, expectedValue2) = ("D", 4)
|
||||
let (actualKey2, actualValue2) = orderedDictionary.remove(at: 2)!
|
||||
let (expectedKey2, expectedValue2) = ("D", 4)
|
||||
|
||||
XCTAssertEqual(expectedKey2, actualKey2)
|
||||
XCTAssertEqual(expectedValue2, actualValue2)
|
||||
XCTAssertEqual(actualKey2, expectedKey2)
|
||||
XCTAssertEqual(actualValue2, expectedValue2)
|
||||
|
||||
let nonExistentElement = orderedDictionary.remove(at: 42)
|
||||
|
||||
XCTAssertNil(nonExistentElement)
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["B": 2, "C": 3]
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["B": 2, "C": 3]
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testPopFirstEmpty() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = []
|
||||
let first = orderedDictionary.popFirst()
|
||||
|
||||
XCTAssertNil(first)
|
||||
}
|
||||
|
||||
func testPopFirstNonEmpty() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let (actualKey, actualValue) = orderedDictionary.popFirst()!
|
||||
let (expectedKey, expectedValue) = ("A", 1)
|
||||
|
||||
XCTAssertEqual(actualKey, expectedKey)
|
||||
XCTAssertEqual(actualValue, expectedValue)
|
||||
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["B": 2, "C": 3, "D": 4]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testPopLastEmpty() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = []
|
||||
let last = orderedDictionary.popLast()
|
||||
|
||||
XCTAssertNil(last)
|
||||
}
|
||||
|
||||
func testPopLastNonEmpty() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let (actualKey, actualValue) = orderedDictionary.popLast()!
|
||||
let (expectedKey, expectedValue) = ("D", 4)
|
||||
|
||||
XCTAssertEqual(actualKey, expectedKey)
|
||||
XCTAssertEqual(actualValue, expectedValue)
|
||||
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testRemoveFirstNonEmpty() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let (actualKey, actualValue) = orderedDictionary.removeFirst()
|
||||
let (expectedKey, expectedValue) = ("A", 1)
|
||||
|
||||
XCTAssertEqual(actualKey, expectedKey)
|
||||
XCTAssertEqual(actualValue, expectedValue)
|
||||
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["B": 2, "C": 3, "D": 4]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testRemoveLastNonEmpty() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let (actualKey, actualValue) = orderedDictionary.removeLast()
|
||||
let (expectedKey, expectedValue) = ("D", 4)
|
||||
|
||||
XCTAssertEqual(actualKey, expectedKey)
|
||||
XCTAssertEqual(actualValue, expectedValue)
|
||||
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -370,38 +479,58 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["C": 3, "A": 1, "D": 4, "B": 2]
|
||||
|
||||
XCTAssert(actual == expected)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Sorting Elements
|
||||
// ======================================================= //
|
||||
|
||||
private let areInIncreasingOrder: (OrderedDictionary<String, Int>.Element, OrderedDictionary<String, Int>.Element) -> Bool = { element1, element2 in
|
||||
if element1.value == element2.value {
|
||||
return element1.key < element2.key
|
||||
} else {
|
||||
return element1.value < element2.value
|
||||
}
|
||||
}
|
||||
|
||||
func testSortingWithMutation() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["E": 4, "G": 3, "A": 3, "D": 1, "B": 4]
|
||||
orderedDictionary.sort(by: areInIncreasingOrder)
|
||||
orderedDictionary.sort { element1, element2 in
|
||||
if element1.value != element2.value { return element1.value < element2.value }
|
||||
return element1.key < element2.key
|
||||
}
|
||||
let actual = orderedDictionary
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["D": 1, "A": 3, "G": 3, "B": 4, "E": 4]
|
||||
|
||||
XCTAssertTrue(actual == expected)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testSortingWithoutMutation() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["E": 4, "G": 3, "A": 3, "D": 1, "B": 4]
|
||||
let actual: OrderedDictionary<String, Int> = orderedDictionary.sorted(by: areInIncreasingOrder)
|
||||
let actual: OrderedDictionary<String, Int> = orderedDictionary.sorted { element1, element2 in
|
||||
if element1.value != element2.value { return element1.value < element2.value }
|
||||
return element1.key < element2.key
|
||||
}
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["D": 1, "A": 3, "G": 3, "B": 4, "E": 4]
|
||||
|
||||
XCTAssertTrue(actual.elementsEqual(expected, by: ==))
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Mapping Values
|
||||
// ======================================================= //
|
||||
|
||||
func testMapValues() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let actual = orderedDictionary.mapValues { String($0) }
|
||||
let expected: OrderedDictionary<String, String> = ["A": "1", "B": "2", "C": "3", "D": "4"]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testCompactMapValues() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let actual = orderedDictionary.compactMapValues { $0 % 2 == 0 ? String($0) : nil }
|
||||
let expected: OrderedDictionary<String, String> = ["B": "2", "D": "4"]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -420,6 +549,46 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
XCTAssert(slice[3] == (key: "D", value: 4))
|
||||
}
|
||||
|
||||
// ============================================================================ //
|
||||
// MARK: - Capacity
|
||||
// ============================================================================ //
|
||||
|
||||
func testCapacityReservationViaInit() {
|
||||
let orderedDictionary = OrderedDictionary<String, Int>(minimumCapacity: 10)
|
||||
|
||||
XCTAssertGreaterThanOrEqual(orderedDictionary.capacity, 10)
|
||||
}
|
||||
|
||||
func testCapacityReservationViaMethod() {
|
||||
var orderedDictionary = OrderedDictionary<String, Int>()
|
||||
|
||||
XCTAssertEqual(orderedDictionary.capacity, 0)
|
||||
|
||||
orderedDictionary.reserveCapacity(10)
|
||||
|
||||
XCTAssertGreaterThanOrEqual(orderedDictionary.capacity, 10)
|
||||
XCTAssertLessThan(orderedDictionary.capacity, 20)
|
||||
|
||||
orderedDictionary.reserveCapacity(20)
|
||||
|
||||
XCTAssertGreaterThanOrEqual(orderedDictionary.capacity, 20)
|
||||
}
|
||||
|
||||
func testCapacityGrowForElementInsertion() {
|
||||
var orderedDictionary = OrderedDictionary<String, Int>()
|
||||
|
||||
XCTAssertEqual(orderedDictionary.capacity, 0)
|
||||
|
||||
orderedDictionary["A"] = 1
|
||||
|
||||
XCTAssertEqual(orderedDictionary.capacity, 1)
|
||||
|
||||
orderedDictionary["B"] = 2
|
||||
orderedDictionary["A"] = 3
|
||||
|
||||
XCTAssertEqual(orderedDictionary.capacity, 2)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Codable
|
||||
// ======================================================= //
|
||||
@@ -433,18 +602,18 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
|
||||
let jsonEncoder = JSONEncoder()
|
||||
let data = try! jsonEncoder.encode(orderedDictionary)
|
||||
|
||||
let expectedString = "[\"A\",42,\"B\",100,\"C\",11]"
|
||||
let actualString = String(data: data, encoding: .utf8)
|
||||
|
||||
XCTAssertEqual(expectedString, actualString)
|
||||
let expectedString = "[\"A\",42,\"B\",100,\"C\",11]"
|
||||
|
||||
XCTAssertEqual(actualString, expectedString)
|
||||
|
||||
let jsonDecoder = JSONDecoder()
|
||||
|
||||
let expected = orderedDictionary
|
||||
let actual = try! jsonDecoder.decode(OrderedDictionary<String, Int>.self, from: data)
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = orderedDictionary
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testEncodingAndDecodingViaPropertyList() {
|
||||
@@ -455,14 +624,14 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
]
|
||||
|
||||
let plistEncoder = PropertyListEncoder()
|
||||
let plistDecoder = PropertyListDecoder()
|
||||
|
||||
let data = try! plistEncoder.encode(orderedDictionary)
|
||||
|
||||
let expected = orderedDictionary
|
||||
let plistDecoder = PropertyListDecoder()
|
||||
let actual = try! plistDecoder.decode(OrderedDictionary<String, Int>.self, from: data)
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = orderedDictionary
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -477,39 +646,47 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testEmptyDescription() {
|
||||
let expected = "[:]"
|
||||
|
||||
let orderedDictionary = OrderedDictionary<String, DescribedValue>()
|
||||
let actual = orderedDictionary.description
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = "[:]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testDescription() {
|
||||
let expected = "[A: 1, B: 2, C: 3]"
|
||||
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = ["A": DescribedValue(1), "B": DescribedValue(2), "C": DescribedValue(3)]
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = [
|
||||
"A": DescribedValue(1),
|
||||
"B": DescribedValue(2),
|
||||
"C": DescribedValue(3)
|
||||
]
|
||||
let actual = orderedDictionary.description
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = "[A: 1, B: 2, C: 3]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testEmptyDebugDescription() {
|
||||
let expected = "[:]"
|
||||
|
||||
let orderedDictionary = OrderedDictionary<String, DescribedValue>()
|
||||
let actual = orderedDictionary.debugDescription
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = "[:]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testDebugDescription() {
|
||||
let expected = "[\"A\": debug(1), \"B\": debug(2), \"C\": debug(3)]"
|
||||
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = ["A": DescribedValue(1), "B": DescribedValue(2), "C": DescribedValue(3)]
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = [
|
||||
"A": DescribedValue(1),
|
||||
"B": DescribedValue(2),
|
||||
"C": DescribedValue(3)
|
||||
]
|
||||
let actual = orderedDictionary.debugDescription
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = "[\"A\": debug(1), \"B\": debug(2), \"C\": debug(3)]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user