Compare commits
127 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 9821943fff | |||
| d609a252f8 | |||
| 642d7e34f4 | |||
| 9faf5ab0ea | |||
| f1a207a3e6 | |||
| aeac204817 | |||
| 32ef58d871 | |||
| 6ee0ceaa48 | |||
| 0b6c95022e | |||
| b733108558 | |||
| 14cb718fe2 | |||
| 77dbbf1c1f | |||
| 4be64d3c09 | |||
| 2699924867 | |||
| 87b46f36e1 | |||
| 28cd25d536 | |||
| 122814a5cd | |||
| b49641a892 | |||
| f8630257e6 | |||
| 46d4c52934 | |||
| fb66d1e9d8 | |||
| 638d4ae0d1 | |||
| f3d18a63fa | |||
| d01a024ae7 | |||
| a9a37b7978 | |||
| d87cac83e5 | |||
| 754d4096da | |||
| c5d09d3bc0 | |||
| 5877a0a683 | |||
| 5b6c8e3541 | |||
| 502a9e128e | |||
| be22dfd473 | |||
| a027b5c88b | |||
| 5f71a748f5 | |||
| 220b435d2a | |||
| 1120534fde | |||
| 3dfa4db66a | |||
| 3fe91a8722 | |||
| efb886e6c9 | |||
| a0b52c1d28 | |||
| ccb19e2f1d | |||
| 7d2362fe63 | |||
| 117efdb7bd | |||
| d84ddf7f40 | |||
| 73ee947220 | |||
| 9715568f02 | |||
| 751bbe1bcc | |||
| af87ceac65 | |||
| 99f26c7f93 | |||
| 8e43c679de | |||
| b18549782d | |||
| 5b4de32ee2 | |||
| 64924a208c | |||
| 310c182dc3 | |||
| c7ac65504d | |||
| ce50489b8f | |||
| b6d563a3cc | |||
| bb3ee42176 | |||
| b0251e74d3 | |||
| c8d61b939b | |||
| b832b9925c | |||
| 21b9930d36 | |||
| f81ab4e6a0 | |||
| f53a24821a | |||
| a742de8c3d | |||
| 855e6f6a0f | |||
| 6cd117b224 | |||
| dd71f6e196 | |||
| a63943c0ae | |||
| 3d78836dcd | |||
| be180eeaf4 | |||
| 8a2127d8f4 | |||
| 616815b08c | |||
| 90c35cb532 | |||
| b892a31bd9 | |||
| 699727683d | |||
| 8efd15b99a | |||
| a043a863a7 | |||
| ccdb7bf482 | |||
| c5a5e91d2f | |||
| b53a974021 | |||
| 066b38d0ec | |||
| 8b9d033d7d | |||
| befb924574 | |||
| e9fa5e8191 | |||
| fa8cb4d120 | |||
| d7daeb0518 | |||
| 9b6c798a17 | |||
| 959f4f0eb1 | |||
| 040aadd65f | |||
| b6a99e3ffe | |||
| 20d4d7e7c4 | |||
| a8a69e4570 | |||
| cea6cb0952 | |||
| fae6eb2617 |
@@ -27,3 +27,6 @@ DerivedData
|
||||
|
||||
# Carthage
|
||||
Carthage
|
||||
|
||||
# SPM
|
||||
.build
|
||||
|
||||
+46
-10
@@ -1,13 +1,49 @@
|
||||
language: objective-c
|
||||
osx_image: xcode7.3
|
||||
|
||||
xcode_project: OrderedDictionary.xcodeproj
|
||||
xcode_scheme: OrderedDictionary-iOS
|
||||
xcode_sdk: iphonesimulator
|
||||
|
||||
# Git
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
only:
|
||||
- master
|
||||
|
||||
# OS
|
||||
os: osx
|
||||
language: objective-c
|
||||
|
||||
# Xcode Project
|
||||
xcode_project: OrderedDictionary.xcodeproj
|
||||
|
||||
# Build Matrix
|
||||
matrix:
|
||||
include:
|
||||
# Swift 4.0 / 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 / iOS
|
||||
- osx_image: xcode9.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
|
||||
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
|
||||
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"
|
||||
|
||||
# Build Script
|
||||
script:
|
||||
- xcodebuild clean build test -project OrderedDictionary.xcodeproj -scheme OrderedDictionary-iOS -destination "platform=iOS Simulator,name=iPhone 6,OS=9.0"
|
||||
- Scripts/build.sh
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2016 Lukas Kubanek
|
||||
Copyright (c) 2015-2019 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,224 +7,228 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
803F9CD51B92324C002F728F /* OrderedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 803F9CD21B92324C002F728F /* OrderedDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
803F9CD81B9232EE002F728F /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803F9CD71B9232EE002F728F /* OrderedDictionary.swift */; };
|
||||
803F9CF41B925B1C002F728F /* OrderedDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 803F9CC61B923207002F728F /* OrderedDictionary.framework */; };
|
||||
803F9CFD1B925B4C002F728F /* OrderedDictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803F9CFC1B925B4C002F728F /* OrderedDictionaryTests.swift */; };
|
||||
8060976B1B92F2D200DB20CF /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803F9CD71B9232EE002F728F /* OrderedDictionary.swift */; };
|
||||
8060976C1B92F2D900DB20CF /* OrderedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 803F9CD21B92324C002F728F /* OrderedDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
806097761B92F44F00DB20CF /* OrderedDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 806097631B92F20400DB20CF /* OrderedDictionary.framework */; };
|
||||
8060977C1B92F4A000DB20CF /* OrderedDictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 803F9CFC1B925B4C002F728F /* OrderedDictionaryTests.swift */; };
|
||||
8055B0421E201C5D009DC3EE /* OrderedDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8055B0381E201C5D009DC3EE /* OrderedDictionary.framework */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
80E8E2301E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E8E22F1E2133D100395E49 /* OrderedDictionary+Description.swift */; };
|
||||
80E8E2311E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E8E22F1E2133D100395E49 /* OrderedDictionary+Description.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
803F9CF51B925B1C002F728F /* PBXContainerItemProxy */ = {
|
||||
8055B0431E201C5D009DC3EE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 803F9CBD1B923207002F728F /* Project object */;
|
||||
containerPortal = 8055B02F1E201C5D009DC3EE /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 803F9CC51B923207002F728F;
|
||||
remoteGlobalIDString = 8055B0371E201C5D009DC3EE;
|
||||
remoteInfo = OrderedDictionary;
|
||||
};
|
||||
806097771B92F44F00DB20CF /* PBXContainerItemProxy */ = {
|
||||
80B28EA11E201EC9007E3A77 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 803F9CBD1B923207002F728F /* Project object */;
|
||||
containerPortal = 8055B02F1E201C5D009DC3EE /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 806097621B92F20400DB20CF;
|
||||
remoteGlobalIDString = 80B28E961E201EC8007E3A77;
|
||||
remoteInfo = "OrderedDictionary-iOS";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
803F9CFF1B925BA2002F728F /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
806097811B92F4F500DB20CF /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
803F9CC61B923207002F728F /* OrderedDictionary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OrderedDictionary.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
803F9CD21B92324C002F728F /* OrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OrderedDictionary.h; sourceTree = "<group>"; };
|
||||
803F9CD41B92324C002F728F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
803F9CD71B9232EE002F728F /* OrderedDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderedDictionary.swift; sourceTree = "<group>"; };
|
||||
803F9CEF1B925B1C002F728F /* OrderedDictionary-OSX-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OrderedDictionary-OSX-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
803F9CFC1B925B4C002F728F /* OrderedDictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderedDictionaryTests.swift; sourceTree = "<group>"; };
|
||||
803F9CFE1B925B56002F728F /* Info-Tests.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-Tests.plist"; sourceTree = "<group>"; };
|
||||
806097631B92F20400DB20CF /* OrderedDictionary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OrderedDictionary.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
806097711B92F44F00DB20CF /* OrderedDictionary-iOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OrderedDictionary-iOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
80F94F181B926A60000A96E7 /* OrderedDictionary.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = OrderedDictionary.playground; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
80B28E971E201EC8007E3A77 /* OrderedDictionary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OrderedDictionary.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
80B28E9F1E201EC9007E3A77 /* OrderedDictionary_iOS_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OrderedDictionary_iOS_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
803F9CC21B923207002F728F /* Frameworks */ = {
|
||||
8055B0341E201C5D009DC3EE /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
803F9CEC1B925B1C002F728F /* Frameworks */ = {
|
||||
8055B03E1E201C5D009DC3EE /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
803F9CF41B925B1C002F728F /* OrderedDictionary.framework in Frameworks */,
|
||||
8055B0421E201C5D009DC3EE /* OrderedDictionary.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8060975F1B92F20400DB20CF /* Frameworks */ = {
|
||||
80B28E931E201EC8007E3A77 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8060976E1B92F44F00DB20CF /* Frameworks */ = {
|
||||
80B28E9C1E201EC9007E3A77 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
806097761B92F44F00DB20CF /* OrderedDictionary.framework in Frameworks */,
|
||||
80B28EA01E201EC9007E3A77 /* OrderedDictionary.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
803F9CBC1B923207002F728F = {
|
||||
804879361E217C7700AD31A3 /* Scripts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
803F9CD11B92324C002F728F /* Sources */,
|
||||
803F9CFB1B925B4C002F728F /* Tests */,
|
||||
80F94F171B926A60000A96E7 /* Playgrounds */,
|
||||
803F9CD31B92324C002F728F /* Supporting Files */,
|
||||
803F9CC71B923207002F728F /* Products */,
|
||||
804879371E217C7700AD31A3 /* build.sh */,
|
||||
804879381E217CA100AD31A3 /* validate-playgrounds.sh */,
|
||||
);
|
||||
path = Scripts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 */,
|
||||
80B28EB31E201F81007E3A77 /* Supporting Files */,
|
||||
804879361E217C7700AD31A3 /* Scripts */,
|
||||
8055B0391E201C5D009DC3EE /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
803F9CC71B923207002F728F /* Products */ = {
|
||||
8055B0391E201C5D009DC3EE /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
803F9CC61B923207002F728F /* OrderedDictionary.framework */,
|
||||
803F9CEF1B925B1C002F728F /* OrderedDictionary-OSX-Tests.xctest */,
|
||||
806097631B92F20400DB20CF /* OrderedDictionary.framework */,
|
||||
806097711B92F44F00DB20CF /* OrderedDictionary-iOS-Tests.xctest */,
|
||||
8055B0381E201C5D009DC3EE /* OrderedDictionary.framework */,
|
||||
8055B0411E201C5D009DC3EE /* OrderedDictionary_Mac_Tests.xctest */,
|
||||
80B28E971E201EC8007E3A77 /* OrderedDictionary.framework */,
|
||||
80B28E9F1E201EC9007E3A77 /* OrderedDictionary_iOS_Tests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
803F9CD11B92324C002F728F /* Sources */ = {
|
||||
8055B0521E201D24009DC3EE /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
803F9CD21B92324C002F728F /* OrderedDictionary.h */,
|
||||
803F9CD71B9232EE002F728F /* OrderedDictionary.swift */,
|
||||
80E8E21C1E20301E00395E49 /* OrderedDictionary.swift */,
|
||||
80A203A01F3F483700622481 /* OrderedDictionary+Codable.swift */,
|
||||
80E8E22F1E2133D100395E49 /* OrderedDictionary+Description.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
803F9CD31B92324C002F728F /* Supporting Files */ = {
|
||||
8055B0571E201DF3009DC3EE /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
803F9CFE1B925B56002F728F /* Info-Tests.plist */,
|
||||
803F9CD41B92324C002F728F /* Info.plist */,
|
||||
);
|
||||
path = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
803F9CFB1B925B4C002F728F /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
803F9CFC1B925B4C002F728F /* OrderedDictionaryTests.swift */,
|
||||
8055B0581E201DF3009DC3EE /* OrderedDictionaryTests.swift */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
80F94F171B926A60000A96E7 /* Playgrounds */ = {
|
||||
80B28EB11E201F72007E3A77 /* Playgrounds */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
80F94F181B926A60000A96E7 /* OrderedDictionary.playground */,
|
||||
80B28EB71E2020DD007E3A77 /* OrderedDictionary.playground */,
|
||||
807AA68F1F1E587A00576474 /* OrderedDictionary+Codable.playground */,
|
||||
);
|
||||
path = Playgrounds;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
80B28EB31E201F81007E3A77 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
80B28EB51E201F81007E3A77 /* Info.plist */,
|
||||
80B28EB41E201F81007E3A77 /* Info-Tests.plist */,
|
||||
);
|
||||
path = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
803F9CC31B923207002F728F /* Headers */ = {
|
||||
8055B0351E201C5D009DC3EE /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
803F9CD51B92324C002F728F /* OrderedDictionary.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
806097601B92F20400DB20CF /* Headers */ = {
|
||||
80B28E941E201EC8007E3A77 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8060976C1B92F2D900DB20CF /* OrderedDictionary.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
803F9CC51B923207002F728F /* OrderedDictionary-OSX */ = {
|
||||
8055B0371E201C5D009DC3EE /* OrderedDictionary-Mac */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 803F9CCE1B923207002F728F /* Build configuration list for PBXNativeTarget "OrderedDictionary-OSX" */;
|
||||
buildConfigurationList = 8055B04C1E201C5D009DC3EE /* Build configuration list for PBXNativeTarget "OrderedDictionary-Mac" */;
|
||||
buildPhases = (
|
||||
803F9CC11B923207002F728F /* Sources */,
|
||||
803F9CC21B923207002F728F /* Frameworks */,
|
||||
803F9CC31B923207002F728F /* Headers */,
|
||||
803F9CC41B923207002F728F /* Resources */,
|
||||
8055B0331E201C5D009DC3EE /* Sources */,
|
||||
8055B0341E201C5D009DC3EE /* Frameworks */,
|
||||
8055B0351E201C5D009DC3EE /* Headers */,
|
||||
8055B0361E201C5D009DC3EE /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "OrderedDictionary-OSX";
|
||||
name = "OrderedDictionary-Mac";
|
||||
productName = OrderedDictionary;
|
||||
productReference = 803F9CC61B923207002F728F /* OrderedDictionary.framework */;
|
||||
productReference = 8055B0381E201C5D009DC3EE /* OrderedDictionary.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
803F9CEE1B925B1C002F728F /* OrderedDictionary-OSX-Tests */ = {
|
||||
8055B0401E201C5D009DC3EE /* OrderedDictionary-Mac-Tests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 803F9CF71B925B1C002F728F /* Build configuration list for PBXNativeTarget "OrderedDictionary-OSX-Tests" */;
|
||||
buildConfigurationList = 8055B04F1E201C5D009DC3EE /* Build configuration list for PBXNativeTarget "OrderedDictionary-Mac-Tests" */;
|
||||
buildPhases = (
|
||||
803F9CEB1B925B1C002F728F /* Sources */,
|
||||
803F9CEC1B925B1C002F728F /* Frameworks */,
|
||||
803F9CED1B925B1C002F728F /* Resources */,
|
||||
803F9CFF1B925BA2002F728F /* CopyFiles */,
|
||||
8055B03D1E201C5D009DC3EE /* Sources */,
|
||||
8055B03E1E201C5D009DC3EE /* Frameworks */,
|
||||
8055B03F1E201C5D009DC3EE /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
803F9CF61B925B1C002F728F /* PBXTargetDependency */,
|
||||
8055B0441E201C5D009DC3EE /* PBXTargetDependency */,
|
||||
);
|
||||
name = "OrderedDictionary-OSX-Tests";
|
||||
name = "OrderedDictionary-Mac-Tests";
|
||||
productName = OrderedDictionaryTests;
|
||||
productReference = 803F9CEF1B925B1C002F728F /* OrderedDictionary-OSX-Tests.xctest */;
|
||||
productReference = 8055B0411E201C5D009DC3EE /* OrderedDictionary_Mac_Tests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
806097621B92F20400DB20CF /* OrderedDictionary-iOS */ = {
|
||||
80B28E961E201EC8007E3A77 /* OrderedDictionary-iOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 806097681B92F20400DB20CF /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS" */;
|
||||
buildConfigurationList = 80B28EA81E201EC9007E3A77 /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS" */;
|
||||
buildPhases = (
|
||||
8060975E1B92F20400DB20CF /* Sources */,
|
||||
8060975F1B92F20400DB20CF /* Frameworks */,
|
||||
806097601B92F20400DB20CF /* Headers */,
|
||||
806097611B92F20400DB20CF /* Resources */,
|
||||
80B28E921E201EC8007E3A77 /* Sources */,
|
||||
80B28E931E201EC8007E3A77 /* Frameworks */,
|
||||
80B28E941E201EC8007E3A77 /* Headers */,
|
||||
80B28E951E201EC8007E3A77 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -232,95 +236,103 @@
|
||||
);
|
||||
name = "OrderedDictionary-iOS";
|
||||
productName = "OrderedDictionary-iOS";
|
||||
productReference = 806097631B92F20400DB20CF /* OrderedDictionary.framework */;
|
||||
productReference = 80B28E971E201EC8007E3A77 /* OrderedDictionary.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
806097701B92F44F00DB20CF /* OrderedDictionary-iOS-Tests */ = {
|
||||
80B28E9E1E201EC9007E3A77 /* OrderedDictionary-iOS-Tests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 806097791B92F44F00DB20CF /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS-Tests" */;
|
||||
buildConfigurationList = 80B28EAB1E201EC9007E3A77 /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS-Tests" */;
|
||||
buildPhases = (
|
||||
8060976D1B92F44F00DB20CF /* Sources */,
|
||||
8060976E1B92F44F00DB20CF /* Frameworks */,
|
||||
8060976F1B92F44F00DB20CF /* Resources */,
|
||||
806097811B92F4F500DB20CF /* CopyFiles */,
|
||||
80B28E9B1E201EC9007E3A77 /* Sources */,
|
||||
80B28E9C1E201EC9007E3A77 /* Frameworks */,
|
||||
80B28E9D1E201EC9007E3A77 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
806097781B92F44F00DB20CF /* PBXTargetDependency */,
|
||||
80B28EA21E201EC9007E3A77 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "OrderedDictionary-iOS-Tests";
|
||||
productName = "OrderedDictionary-iOS-Tests";
|
||||
productReference = 806097711B92F44F00DB20CF /* OrderedDictionary-iOS-Tests.xctest */;
|
||||
productName = "OrderedDictionary-iOSTests";
|
||||
productReference = 80B28E9F1E201EC9007E3A77 /* OrderedDictionary_iOS_Tests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
803F9CBD1B923207002F728F /* Project object */ = {
|
||||
8055B02F1E201C5D009DC3EE /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0700;
|
||||
LastSwiftUpdateCheck = 0820;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = "Lukas Kubanek";
|
||||
TargetAttributes = {
|
||||
803F9CC51B923207002F728F = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
8055B0371E201C5D009DC3EE = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
803F9CEE1B925B1C002F728F = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
8055B0401E201C5D009DC3EE = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
806097621B92F20400DB20CF = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
80B28E961E201EC8007E3A77 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
806097701B92F44F00DB20CF = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
80B28E9E1E201EC9007E3A77 = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 803F9CC01B923207002F728F /* Build configuration list for PBXProject "OrderedDictionary" */;
|
||||
buildConfigurationList = 8055B0321E201C5D009DC3EE /* Build configuration list for PBXProject "OrderedDictionary" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 803F9CBC1B923207002F728F;
|
||||
productRefGroup = 803F9CC71B923207002F728F /* Products */;
|
||||
mainGroup = 8055B02E1E201C5D009DC3EE;
|
||||
productRefGroup = 8055B0391E201C5D009DC3EE /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
803F9CC51B923207002F728F /* OrderedDictionary-OSX */,
|
||||
803F9CEE1B925B1C002F728F /* OrderedDictionary-OSX-Tests */,
|
||||
806097621B92F20400DB20CF /* OrderedDictionary-iOS */,
|
||||
806097701B92F44F00DB20CF /* OrderedDictionary-iOS-Tests */,
|
||||
8055B0371E201C5D009DC3EE /* OrderedDictionary-Mac */,
|
||||
8055B0401E201C5D009DC3EE /* OrderedDictionary-Mac-Tests */,
|
||||
80B28E961E201EC8007E3A77 /* OrderedDictionary-iOS */,
|
||||
80B28E9E1E201EC9007E3A77 /* OrderedDictionary-iOS-Tests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
803F9CC41B923207002F728F /* Resources */ = {
|
||||
8055B0361E201C5D009DC3EE /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
803F9CED1B925B1C002F728F /* Resources */ = {
|
||||
8055B03F1E201C5D009DC3EE /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
806097611B92F20400DB20CF /* Resources */ = {
|
||||
80B28E951E201EC8007E3A77 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8060976F1B92F44F00DB20CF /* Resources */ = {
|
||||
80B28E9D1E201EC9007E3A77 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -330,71 +342,89 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
803F9CC11B923207002F728F /* Sources */ = {
|
||||
8055B0331E201C5D009DC3EE /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
803F9CD81B9232EE002F728F /* OrderedDictionary.swift in Sources */,
|
||||
80E8E2301E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */,
|
||||
80E8E21D1E20301E00395E49 /* OrderedDictionary.swift in Sources */,
|
||||
80A203A11F3F483700622481 /* OrderedDictionary+Codable.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
803F9CEB1B925B1C002F728F /* Sources */ = {
|
||||
8055B03D1E201C5D009DC3EE /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
803F9CFD1B925B4C002F728F /* OrderedDictionaryTests.swift in Sources */,
|
||||
8055B0591E201DF3009DC3EE /* OrderedDictionaryTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8060975E1B92F20400DB20CF /* Sources */ = {
|
||||
80B28E921E201EC8007E3A77 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8060976B1B92F2D200DB20CF /* OrderedDictionary.swift in Sources */,
|
||||
80E8E2311E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */,
|
||||
80E8E21F1E20425B00395E49 /* OrderedDictionary.swift in Sources */,
|
||||
80A203A21F3F4C1F00622481 /* OrderedDictionary+Codable.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
8060976D1B92F44F00DB20CF /* Sources */ = {
|
||||
80B28E9B1E201EC9007E3A77 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8060977C1B92F4A000DB20CF /* OrderedDictionaryTests.swift in Sources */,
|
||||
80B28EB01E201F1C007E3A77 /* OrderedDictionaryTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
803F9CF61B925B1C002F728F /* PBXTargetDependency */ = {
|
||||
8055B0441E201C5D009DC3EE /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 803F9CC51B923207002F728F /* OrderedDictionary-OSX */;
|
||||
targetProxy = 803F9CF51B925B1C002F728F /* PBXContainerItemProxy */;
|
||||
target = 8055B0371E201C5D009DC3EE /* OrderedDictionary-Mac */;
|
||||
targetProxy = 8055B0431E201C5D009DC3EE /* PBXContainerItemProxy */;
|
||||
};
|
||||
806097781B92F44F00DB20CF /* PBXTargetDependency */ = {
|
||||
80B28EA21E201EC9007E3A77 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 806097621B92F20400DB20CF /* OrderedDictionary-iOS */;
|
||||
targetProxy = 806097771B92F44F00DB20CF /* PBXContainerItemProxy */;
|
||||
target = 80B28E961E201EC8007E3A77 /* OrderedDictionary-iOS */;
|
||||
targetProxy = 80B28EA11E201EC9007E3A77 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
803F9CCC1B923207002F728F /* Debug */ = {
|
||||
8055B04A1E201C5D009DC3EE /* Debug */ = {
|
||||
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++";
|
||||
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_DOCUMENTATION_COMMENTS = YES;
|
||||
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 = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
@@ -419,29 +449,46 @@
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
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 = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
803F9CCD1B923207002F728F /* Release */ = {
|
||||
8055B04B1E201C5D009DC3EE /* Release */ = {
|
||||
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++";
|
||||
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_DOCUMENTATION_COMMENTS = YES;
|
||||
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 = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
@@ -459,92 +506,93 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
803F9CCF1B923207002F728F /* Debug */ = {
|
||||
8055B04D1E201C5D009DC3EE /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
FRAMEWORK_VERSION = A;
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionary;
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
803F9CD01B923207002F728F /* Release */ = {
|
||||
8055B04E1E201C5D009DC3EE /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
FRAMEWORK_VERSION = A;
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionary;
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
803F9CF81B925B1C002F728F /* Debug */ = {
|
||||
8055B0501E201C5D009DC3EE /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = "Supporting Files/Info-Tests.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionaryTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
803F9CF91B925B1C002F728F /* Release */ = {
|
||||
8055B0511E201C5D009DC3EE /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = "Supporting Files/Info-Tests.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionaryTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
806097691B92F20400DB20CF /* Debug */ = {
|
||||
80B28EA91E201EC9007E3A77 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionary;
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
@@ -554,18 +602,19 @@
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
8060976A1B92F20400DB20CF /* Release */ = {
|
||||
80B28EAA1E201EC9007E3A77 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CLANG_ENABLE_CODE_COVERAGE = NO;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lukaskubanek.OrderedDictionary;
|
||||
PRODUCT_NAME = OrderedDictionary;
|
||||
@@ -576,28 +625,26 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
8060977A1B92F44F00DB20CF /* Debug */ = {
|
||||
80B28EAC1E201EC9007E3A77 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
INFOPLIST_FILE = "Supporting Files/Info-Tests.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.lukaskubanek.OrderedDictionary-iOS-Tests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.lukaskubanek.OrderedDictionary-iOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
8060977B1B92F44F00DB20CF /* Release */ = {
|
||||
80B28EAD1E201EC9007E3A77 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
INFOPLIST_FILE = "Supporting Files/Info-Tests.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.lukaskubanek.OrderedDictionary-iOS-Tests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.lukaskubanek.OrderedDictionary-iOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
@@ -606,52 +653,52 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
803F9CC01B923207002F728F /* Build configuration list for PBXProject "OrderedDictionary" */ = {
|
||||
8055B0321E201C5D009DC3EE /* Build configuration list for PBXProject "OrderedDictionary" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
803F9CCC1B923207002F728F /* Debug */,
|
||||
803F9CCD1B923207002F728F /* Release */,
|
||||
8055B04A1E201C5D009DC3EE /* Debug */,
|
||||
8055B04B1E201C5D009DC3EE /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
803F9CCE1B923207002F728F /* Build configuration list for PBXNativeTarget "OrderedDictionary-OSX" */ = {
|
||||
8055B04C1E201C5D009DC3EE /* Build configuration list for PBXNativeTarget "OrderedDictionary-Mac" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
803F9CCF1B923207002F728F /* Debug */,
|
||||
803F9CD01B923207002F728F /* Release */,
|
||||
8055B04D1E201C5D009DC3EE /* Debug */,
|
||||
8055B04E1E201C5D009DC3EE /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
803F9CF71B925B1C002F728F /* Build configuration list for PBXNativeTarget "OrderedDictionary-OSX-Tests" */ = {
|
||||
8055B04F1E201C5D009DC3EE /* Build configuration list for PBXNativeTarget "OrderedDictionary-Mac-Tests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
803F9CF81B925B1C002F728F /* Debug */,
|
||||
803F9CF91B925B1C002F728F /* Release */,
|
||||
8055B0501E201C5D009DC3EE /* Debug */,
|
||||
8055B0511E201C5D009DC3EE /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
806097681B92F20400DB20CF /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS" */ = {
|
||||
80B28EA81E201EC9007E3A77 /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
806097691B92F20400DB20CF /* Debug */,
|
||||
8060976A1B92F20400DB20CF /* Release */,
|
||||
80B28EA91E201EC9007E3A77 /* Debug */,
|
||||
80B28EAA1E201EC9007E3A77 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
806097791B92F44F00DB20CF /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS-Tests" */ = {
|
||||
80B28EAB1E201EC9007E3A77 /* Build configuration list for PBXNativeTarget "OrderedDictionary-iOS-Tests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
8060977A1B92F44F00DB20CF /* Debug */,
|
||||
8060977B1B92F44F00DB20CF /* Release */,
|
||||
80B28EAC1E201EC9007E3A77 /* Debug */,
|
||||
80B28EAD1E201EC9007E3A77 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 803F9CBD1B923207002F728F /* Project object */;
|
||||
rootObject = 8055B02F1E201C5D009DC3EE /* Project object */;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+14
-16
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -11,13 +11,12 @@
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES"
|
||||
hideIssues = "NO">
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "803F9CC51B923207002F728F"
|
||||
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-OSX"
|
||||
BlueprintName = "OrderedDictionary-Mac"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
@@ -27,16 +26,15 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "803F9CEE1B925B1C002F728F"
|
||||
BuildableName = "OrderedDictionary-OSX-Tests.xctest"
|
||||
BlueprintName = "OrderedDictionary-OSX-Tests"
|
||||
BlueprintIdentifier = "8055B0401E201C5D009DC3EE"
|
||||
BuildableName = "OrderedDictionary_Mac_Tests.xctest"
|
||||
BlueprintName = "OrderedDictionary-Mac-Tests"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
@@ -44,9 +42,9 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "803F9CC51B923207002F728F"
|
||||
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-OSX"
|
||||
BlueprintName = "OrderedDictionary-Mac"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -66,9 +64,9 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "803F9CC51B923207002F728F"
|
||||
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-OSX"
|
||||
BlueprintName = "OrderedDictionary-Mac"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -84,9 +82,9 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "803F9CC51B923207002F728F"
|
||||
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-OSX"
|
||||
BlueprintName = "OrderedDictionary-Mac"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -11,11 +11,10 @@
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES"
|
||||
hideIssues = "NO">
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "806097621B92F20400DB20CF"
|
||||
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-iOS"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
@@ -27,15 +26,14 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "806097701B92F44F00DB20CF"
|
||||
BuildableName = "OrderedDictionary-iOS-Tests.xctest"
|
||||
BlueprintIdentifier = "80B28E9E1E201EC9007E3A77"
|
||||
BuildableName = "OrderedDictionary_iOS_Tests.xctest"
|
||||
BlueprintName = "OrderedDictionary-iOS-Tests"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
</BuildableReference>
|
||||
@@ -44,7 +42,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "806097621B92F20400DB20CF"
|
||||
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-iOS"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
@@ -66,7 +64,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "806097621B92F20400DB20CF"
|
||||
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-iOS"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
@@ -84,7 +82,7 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "806097621B92F20400DB20CF"
|
||||
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
|
||||
BuildableName = "OrderedDictionary.framework"
|
||||
BlueprintName = "OrderedDictionary-iOS"
|
||||
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
|
||||
|
||||
@@ -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]
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
import Foundation
|
||||
import OrderedDictionary
|
||||
|
||||
let orderedDictionary1: OrderedDictionary<String, Int> = [
|
||||
"A": 42,
|
||||
"B": 100,
|
||||
"C": 11
|
||||
]
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - JSON Encoding & Decoding
|
||||
// ======================================================= //
|
||||
|
||||
let jsonEncoder = JSONEncoder()
|
||||
let jsonData = try! jsonEncoder.encode(orderedDictionary1)
|
||||
let jsonString = String(data: jsonData, encoding: .utf8)
|
||||
|
||||
let jsonDecoder = JSONDecoder()
|
||||
let orderedDictionary2 = try! jsonDecoder.decode(OrderedDictionary<String, Int>.self, from: jsonData)
|
||||
|
||||
orderedDictionary1 == orderedDictionary2
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Property List Encoding & Decoding
|
||||
// ======================================================= //
|
||||
|
||||
let plistEncoder = PropertyListEncoder()
|
||||
let plistData = try! plistEncoder.encode(orderedDictionary1)
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='macos'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
@@ -1,16 +1,25 @@
|
||||
// Import the framework
|
||||
import OrderedDictionary
|
||||
|
||||
// ======================================================= //
|
||||
// CONSTRUCTION
|
||||
// Helpers
|
||||
// ======================================================= //
|
||||
|
||||
func print(_ optional: Any?) {
|
||||
print(optional as Any)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// Construction
|
||||
// ======================================================= //
|
||||
|
||||
// Construct an ordered dictionary using a dictionary literal
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
// Output the ordered dictionary
|
||||
print(orderedDictionary) // => [A: 1, B: 2, C: 3, D: 4]
|
||||
|
||||
// ======================================================= //
|
||||
// LOOPING
|
||||
// Enumeration
|
||||
// ======================================================= //
|
||||
|
||||
// Loop through the ordered dictionary
|
||||
@@ -19,25 +28,25 @@ for (key, value) in orderedDictionary {
|
||||
}
|
||||
|
||||
// Loop through the ordered dictionary with an additional index
|
||||
for (index, (key, value)) in orderedDictionary.enumerate() {
|
||||
print("(\(index): [\(key): \(value)])") // => (0: [A: 1]), => (1: [B: 2]), => (2: [C: 3]), => (3: [D: 4])
|
||||
for (index, element) in orderedDictionary.enumerated() {
|
||||
print("(\(index): [\(element.key): \(element.value)])") // => (0: [A: 1]), => (1: [B: 2]), => (2: [C: 3]), => (3: [D: 4])
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// ACCESSING CONTENT
|
||||
// Acessing Content
|
||||
// ======================================================= //
|
||||
|
||||
// Access the value for an existing key using subscript
|
||||
// Access the value for an existing key using the subscript
|
||||
print(orderedDictionary["A"]) // => Optional(1)
|
||||
|
||||
// Access the value for a non-existent key
|
||||
// Access the value for a non-existent key using the subscript
|
||||
print(orderedDictionary["X"]) // => nil
|
||||
|
||||
// Access the value for a key using method
|
||||
print(orderedDictionary.valueForKey("A")) // => Optional(1)
|
||||
// Access the value for a key using the method
|
||||
print(orderedDictionary.value(forKey: "A")) // => Optional(1)
|
||||
|
||||
// Access the value for a non-existent key
|
||||
print(orderedDictionary.valueForKey("X")) // => nil
|
||||
// Access the value for a non-existent key using the method
|
||||
print(orderedDictionary.value(forKey: "X")) // => nil
|
||||
|
||||
// Access the key-value pair (element) at an existing index
|
||||
print(orderedDictionary[2]) // => ("C", 3)
|
||||
@@ -46,83 +55,79 @@ print(orderedDictionary[2]) // => ("C", 3)
|
||||
//print(orderedDictionary[10]) // => fatal error
|
||||
|
||||
// Get the index for an existing key
|
||||
print(orderedDictionary.indexForKey("D")) // => Optional(3)
|
||||
print(orderedDictionary.index(forKey: "D")) // => Optional(3)
|
||||
|
||||
// ======================================================= //
|
||||
// MODIFYING CONTENT USING KEYS
|
||||
// Modifying Content Using Keys
|
||||
// ======================================================= //
|
||||
|
||||
// Modify the value for an existing key using subscript
|
||||
// Modify the value for an existing key using the subscript
|
||||
orderedDictionary["A"] = 100
|
||||
print(orderedDictionary["A"]) // => Optional(100)
|
||||
|
||||
// Modify the value for an existing key using method
|
||||
// Modify the value for an existing key using the method
|
||||
orderedDictionary.updateValue(42, forKey: "D")
|
||||
print(orderedDictionary["D"]) // => Optional(42)
|
||||
|
||||
// Set a value for an non-existent key
|
||||
// Append a new key-value pair by setting a value for an non-existent key
|
||||
orderedDictionary["E"] = 5
|
||||
print(orderedDictionary) // => [A: 100, B: 2, C: 3, D: 42, E: 5]
|
||||
|
||||
// Set nil value for an existing key
|
||||
// Remove a key-value pair by setting `nil` value for an existing key
|
||||
orderedDictionary["B"] = nil
|
||||
print(orderedDictionary["B"]) // => nil
|
||||
print(orderedDictionary) // => [A: 100, C: 3, D: 42, E: 5]
|
||||
|
||||
// ======================================================= //
|
||||
// MODIFYING CONTENT USING INDEXES
|
||||
// Modifying Content Using Indexes
|
||||
// ======================================================= //
|
||||
|
||||
// Modify the existing element at index using subscript
|
||||
orderedDictionary[2] = ("F", 235)
|
||||
// Modify an element at an existing index
|
||||
let replacedElement = orderedDictionary.update(("F", 235), at: 2)
|
||||
print(orderedDictionary[2]) // => ("F", 235)
|
||||
print(orderedDictionary) // => [A: 100, C: 3, F: 235, E: 5]
|
||||
print(replacedElement) // => Optional("D", 42)
|
||||
|
||||
// Modify the existing element at index using method
|
||||
let previousElement = orderedDictionary.updateElement(("K", 12), atIndex: 1)
|
||||
print(orderedDictionary[1]) // => ("K", 12)
|
||||
print(previousElement) // => Optional("C", 3)
|
||||
print(orderedDictionary) // => [A: 100, K: 12, F: 235, E: 5]
|
||||
|
||||
// Set an element to a non-existent index
|
||||
//orderedDictionary[100] = ("L", 0) // => fatal error
|
||||
// Modify an element at a non-existent index
|
||||
//orderedDictionary.update(("L", 0), at: 100) // => fatal error
|
||||
|
||||
// ======================================================= //
|
||||
// SORTING
|
||||
// Sorting
|
||||
// ======================================================= //
|
||||
|
||||
// Sort the ordered dictionary using a closure
|
||||
orderedDictionary.sortInPlace { (element1: (key: String, value: Int), element2: (key: String, value: Int)) -> Bool in
|
||||
if element1.value == element2.value {
|
||||
return element1.key < element2.key
|
||||
orderedDictionary.sort {
|
||||
if $0.value == $1.value {
|
||||
return $0.key < $1.key
|
||||
} else {
|
||||
return element1.value < element2.value
|
||||
return $0.value < $1.value
|
||||
}
|
||||
}
|
||||
print(orderedDictionary) // => [E: 5, K: 12, A: 100, F: 235]
|
||||
|
||||
print(orderedDictionary) // => [C: 3, E: 5, A: 100, F: 235]
|
||||
|
||||
// ======================================================= //
|
||||
// REMOVING CONTENT
|
||||
// Removing Content
|
||||
// ======================================================= //
|
||||
|
||||
// Remove value for an existing key
|
||||
let removedValue = orderedDictionary.removeValueForKey("F")
|
||||
let removedValue = orderedDictionary.removeValue(forKey: "F")
|
||||
print(removedValue) // => Optional(235)
|
||||
print(orderedDictionary["F"]) // => nil
|
||||
print(orderedDictionary) // => [E: 5, K: 12, A: 100]
|
||||
print(orderedDictionary) // => [C: 3, E: 5, A: 100]
|
||||
|
||||
// Remove value for a non-existent key
|
||||
orderedDictionary.removeValueForKey("X")
|
||||
print(orderedDictionary) // => [E: 5, K: 12, A: 100]
|
||||
orderedDictionary.removeValue(forKey: "X")
|
||||
print(orderedDictionary) // => [C: 3, E: 5, A: 100]
|
||||
|
||||
// Remove element at an existing index
|
||||
let removedElement = orderedDictionary.removeAtIndex(1)
|
||||
print(removedElement) // => Optional((K, 12))
|
||||
print(orderedDictionary) // => [E: 5, A: 100]
|
||||
let removedElement = orderedDictionary.remove(at: 1)
|
||||
print(removedElement) // => Optional((E, 5))
|
||||
print(orderedDictionary) // => [C: 3, A: 100]
|
||||
|
||||
// Remove element at a non-existent index
|
||||
orderedDictionary.removeAtIndex(42)
|
||||
print(orderedDictionary) // => [E: 5, A: 100]
|
||||
orderedDictionary.remove(at: 42)
|
||||
print(orderedDictionary) // => [C: 3, A: 100]
|
||||
|
||||
// Remove all elements
|
||||
orderedDictionary.removeAll()
|
||||
|
||||
@@ -1,72 +1,64 @@
|
||||
# OrderedDictionary
|
||||
|
||||
[![][image-1]][1] [![][image-2]][2] [![][image-3]][3] ![][image-4] [![][image-5]][4] [![][image-6]][5]
|
||||
[](https://travis-ci.org/lukaskubanek/OrderedDictionary) [](https://github.com/lukaskubanek/OrderedDictionary/releases) [](https://developer.apple.com/swift/ "Swift 4")  [](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.
|
||||
|
||||
The `OrderedDictionary` structure is an immutable generic collection which combines the features of `Dictionary` and `Array` from the Swift standard library. Like `Dictionary` it stores key-value pairs and maps each key to a value. Like `Array` it stores those pairs sorted and accessible by a zero-based integer index.
|
||||
The `OrderedDictionary` struct is a generic collection which combines the features of `Dictionary` and `Array` from the Swift standard library. Like `Dictionary` it stores key-value pairs with each key being unique and maps each key to an associated value. Like `Array` it stores those pairs sorted and accessible by a zero-based integer index.
|
||||
|
||||
`OrderedDictionary` provides similar APIs like collections in the Swift standard library. This includes accessing contents by keys or indexes, inserting and removing elements, iterating, sorting etc.
|
||||
`OrderedDictionary` provides similar APIs like collections from the Swift standard library. This includes accessing contents by keys or indices, inserting and removing elements, iterating, sorting etc.
|
||||
|
||||
Internally `OrderedDictionary` uses a backing store composed of an instance of `Dictionary` for storing the key-value pairs and an instance of `Array` for managing the ordered keys. This means it is not the most performant implementation possible, but it gets its job done by reusing most functionality from the Swift standard library.
|
||||
Internally, `OrderedDictionary` uses a backing store composed of an instance of `Dictionary` for storing the key-value pairs and an instance of `Array` for managing the ordered keys. This means it is not the most performant implementation possible, but it gets its job done by reusing most functionality from the Swift standard library.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Swift 2.2+
|
||||
- Xcode 7.3
|
||||
- iOS 8.0+ / OS X 10.10+
|
||||
- Swift 4.0, 4.2, 5.0
|
||||
- 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][6].
|
||||
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][7] 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][8] and integrating the Xcode project `OrderedDictionary.xcodeproj` directly to your Xcode workspace.
|
||||
#### Swift Package Manager
|
||||
|
||||
## Usage
|
||||
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`:
|
||||
|
||||
For the usage of this library please refer to the [example playground][9].
|
||||
```plain
|
||||
.package(url: "https://github.com/lukaskubanek/OrderedDictionary.git", from: "2.2.2")
|
||||
```
|
||||
|
||||
#### 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
|
||||
|
||||
For the usage of this library please refer to [the example playground](Playgrounds/OrderedDictionary.playground/Contents.swift). For documentation please refer to [the documentation comments](Sources/OrderedDictionary.swift).
|
||||
|
||||
## Changelog
|
||||
|
||||
The changelog is managed on the [GitHub releases page][10].
|
||||
The changelog is managed on the [GitHub releases page](https://github.com/lukaskubanek/OrderedDictionary/releases).
|
||||
|
||||
## Author
|
||||
|
||||
Lukas Kubanek // [lukaskubanek.com][11] // [@kubanekl][12]
|
||||
Lukas Kubanek // [lukaskubanek.com](http://lukaskubanek.com) // [@kubanekl](https://twitter.com/kubanekl)
|
||||
|
||||
## License
|
||||
|
||||
**OrderedDictionary** is provided under the [MIT License][13].
|
||||
|
||||
[1]: https://travis-ci.org/lukaskubanek/OrderedDictionary
|
||||
[2]: https://github.com/lukaskubanek/OrderedDictionary/releases
|
||||
[3]: https://developer.apple.com/swift/
|
||||
[4]: https://github.com/Carthage/Carthage
|
||||
[5]: LICENSE.md
|
||||
[6]: https://github.com/Carthage/Carthage
|
||||
[7]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
|
||||
[8]: http://git-scm.com/book/en/v2/Git-Tools-Submodules
|
||||
[9]: Playgrounds/OrderedDictionary.playground/Contents.swift
|
||||
[10]: https://github.com/lukaskubanek/OrderedDictionary/releases
|
||||
[11]: http://lukaskubanek.com
|
||||
[12]: https://twitter.com/kubanekl
|
||||
[13]: LICENSE.md
|
||||
|
||||
[image-1]: https://img.shields.io/travis/lukaskubanek/OrderedDictionary.svg?style=flat-square "Build"
|
||||
[image-2]: https://img.shields.io/github/release/lukaskubanek/OrderedDictionary.svg?style=flat-square
|
||||
[image-3]: https://img.shields.io/badge/Swift-2.2-orange.svg?style=flat-square "Swift 2.2"
|
||||
[image-4]: https://img.shields.io/badge/platform-osx/ios-yellowgreen.svg?style=flat-square "Platform: OS X, iOS"
|
||||
[image-5]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat-square "Carthage compatible"
|
||||
[image-6]: https://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat-square "License: MIT"
|
||||
**OrderedDictionary** is provided under the [MIT License](LICENSE.md).
|
||||
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script was taken from the ReactiveSwift repository.
|
||||
# https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/script/build
|
||||
|
||||
BUILD_DIRECTORY="build"
|
||||
CONFIGURATION="Release"
|
||||
|
||||
if [[ -z $TRAVIS_XCODE_PROJECT ]]; then
|
||||
echo "Error: \$TRAVIS_XCODE_PROJECT is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $TRAVIS_XCODE_SCHEME ]]; then
|
||||
echo "Error: \$TRAVIS_XCODE_SCHEME is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $XCODE_ACTION ]]; then
|
||||
echo "Error: \$XCODE_ACTION is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $XCODE_SDK ]]; then
|
||||
echo "Error: \$XCODE_SDK is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $XCODE_DESTINATION ]]; then
|
||||
echo "Error: \$XCODE_DESTINATION is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -o pipefail
|
||||
xcodebuild $XCODE_ACTION \
|
||||
-project "$TRAVIS_XCODE_PROJECT" \
|
||||
-scheme "$TRAVIS_XCODE_SCHEME" \
|
||||
-sdk "$XCODE_SDK" \
|
||||
-destination "$XCODE_DESTINATION" \
|
||||
-derivedDataPath "${BUILD_DIRECTORY}" \
|
||||
-configuration $CONFIGURATION \
|
||||
ENABLE_TESTABILITY=YES \
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS=NO \
|
||||
RUN_CLANG_STATIC_ANALYZER=NO | xcpretty
|
||||
result=$?
|
||||
|
||||
if [ "$result" -ne 0 ]; then
|
||||
exit $result
|
||||
fi
|
||||
|
||||
if [[ $XCODE_SDK = "macosx" ]]; then
|
||||
echo "SDK is ${XCODE_SDK}, validating playground..."
|
||||
. Scripts/validate-playgrounds.sh
|
||||
fi
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ -z $BUILD_DIRECTORY ]]; then
|
||||
echo "Error: \$BUILD_DIRECTORY is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $XCODE_PLAYGROUND_TARGET ]]; then
|
||||
echo "Error: \$XCODE_PLAYGROUND_TARGET is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PAGES_PATH=Playgrounds/OrderedDictionary.playground/Contents.swift
|
||||
|
||||
swift -v -target ${XCODE_PLAYGROUND_TARGET} \
|
||||
-D NOT_IN_PLAYGROUND \
|
||||
-F ${BUILD_DIRECTORY}/Build/Products/${CONFIGURATION} ${PAGES_PATH} > /dev/null
|
||||
|
||||
result=$?
|
||||
|
||||
rm -Rf ${BUILD_DIRECTORY}
|
||||
|
||||
exit $result
|
||||
@@ -0,0 +1,136 @@
|
||||
#if swift(>=4.1)
|
||||
|
||||
extension OrderedDictionary: Encodable where Key: Encodable, Value: Encodable {
|
||||
|
||||
/// __inheritdoc__
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
// Encode the ordered dictionary as an array of alternating key-value pairs.
|
||||
var container = encoder.unkeyedContainer()
|
||||
|
||||
for (key, value) in self {
|
||||
try container.encode(key)
|
||||
try container.encode(value)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OrderedDictionary: Decodable where Key: Decodable, Value: Decodable {
|
||||
|
||||
/// __inheritdoc__
|
||||
public init(from decoder: Decoder) throws {
|
||||
// Decode the ordered dictionary from an array of alternating key-value pairs.
|
||||
self.init()
|
||||
|
||||
var container = try decoder.unkeyedContainer()
|
||||
|
||||
while !container.isAtEnd {
|
||||
let key = try container.decode(Key.self)
|
||||
guard !container.isAtEnd else { throw DecodingError.unkeyedContainerReachedEndBeforeValue(decoder.codingPath) }
|
||||
let value = try container.decode(Value.self)
|
||||
|
||||
self[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extension OrderedDictionary: Encodable {
|
||||
|
||||
/// __inheritdoc__
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
// Since Swift 4.0 lacks the protocol conditional conformance support, we have to make the
|
||||
// whole OrderedDictionary type conform to Encodable and assert that the key and value
|
||||
// types conform to Encodable. Furthermore, we leverage a trick of super encoders to be
|
||||
// able to encode objects without knowing their exact types. This trick was used in the
|
||||
// standard library for encoding/decoding Dictionary before Swift 4.1.
|
||||
|
||||
_assertTypeIsEncodable(Key.self, in: type(of: self))
|
||||
_assertTypeIsEncodable(Value.self, in: type(of: self))
|
||||
|
||||
var container = encoder.unkeyedContainer()
|
||||
|
||||
for (key, value) in self {
|
||||
let keyEncoder = container.superEncoder()
|
||||
try (key as! Encodable).encode(to: keyEncoder)
|
||||
|
||||
let valueEncoder = container.superEncoder()
|
||||
try (value as! Encodable).encode(to: valueEncoder)
|
||||
}
|
||||
}
|
||||
|
||||
private func _assertTypeIsEncodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
|
||||
guard T.self is Encodable.Type else {
|
||||
if T.self == Encodable.self || T.self == Codable.self {
|
||||
preconditionFailure("\(wrappingType) does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.")
|
||||
} else {
|
||||
preconditionFailure("\(wrappingType) does not conform to Encodable because \(T.self) does not conform to Encodable.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OrderedDictionary: Decodable {
|
||||
|
||||
/// __inheritdoc__
|
||||
public init(from decoder: Decoder) throws {
|
||||
// Since Swift 4.0 lacks the protocol conditional conformance support, we have to make the
|
||||
// whole OrderedDictionary type conform to Decodable and assert that the key and value
|
||||
// types conform to Decodable. Furthermore, we leverage a trick of super decoders to be
|
||||
// able to decode objects without knowing their exact types. This trick was used in the
|
||||
// standard library for encoding/decoding Dictionary before Swift 4.1.
|
||||
|
||||
self.init()
|
||||
|
||||
_assertTypeIsDecodable(Key.self, in: type(of: self))
|
||||
_assertTypeIsDecodable(Value.self, in: type(of: self))
|
||||
|
||||
var container = try decoder.unkeyedContainer()
|
||||
|
||||
let keyMetaType = (Key.self as! Decodable.Type)
|
||||
let valueMetaType = (Value.self as! Decodable.Type)
|
||||
|
||||
while !container.isAtEnd {
|
||||
let keyDecoder = try container.superDecoder()
|
||||
let key = try keyMetaType.init(from: keyDecoder) as! Key
|
||||
|
||||
guard !container.isAtEnd else { throw DecodingError.unkeyedContainerReachedEndBeforeValue(decoder.codingPath) }
|
||||
|
||||
let valueDecoder = try container.superDecoder()
|
||||
let value = try valueMetaType.init(from: valueDecoder) as! Value
|
||||
|
||||
self[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
private func _assertTypeIsDecodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
|
||||
guard T.self is Decodable.Type else {
|
||||
if T.self == Decodable.self || T.self == Codable.self {
|
||||
preconditionFailure("\(wrappingType) does not conform to Decodable because Decodable does not conform to itself. You must use a concrete type to encode or decode.")
|
||||
} else {
|
||||
preconditionFailure("\(wrappingType) does not conform to Decodable because \(T.self) does not conform to Decodable.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extension DecodingError {
|
||||
|
||||
fileprivate static func unkeyedContainerReachedEndBeforeValue(
|
||||
_ codingPath: [CodingKey]
|
||||
) -> DecodingError {
|
||||
return DecodingError.dataCorrupted(
|
||||
DecodingError.Context(
|
||||
codingPath: codingPath,
|
||||
debugDescription: "Unkeyed container reached end before value in key-value pair."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
extension OrderedDictionary: CustomStringConvertible {
|
||||
|
||||
/// A textual representation of the ordered dictionary.
|
||||
public var description: String {
|
||||
return makeDescription(debug: false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OrderedDictionary: CustomDebugStringConvertible {
|
||||
|
||||
/// A textual representation of the ordered dictionary, suitable for debugging.
|
||||
public var debugDescription: String {
|
||||
return makeDescription(debug: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OrderedDictionary {
|
||||
|
||||
fileprivate func makeDescription(debug: Bool) -> String {
|
||||
// The implementation of the description is inspired by zwaldowski's implementation of the
|
||||
// ordered dictionary. See https://bit.ly/2RiWfJu
|
||||
|
||||
if isEmpty { return "[:]" }
|
||||
|
||||
let printFunction: (Any, inout String) -> () = {
|
||||
if debug {
|
||||
return { debugPrint($0, separator: "", terminator: "", to: &$1) }
|
||||
} else {
|
||||
return { print($0, separator: "", terminator: "", to: &$1) }
|
||||
}
|
||||
}()
|
||||
|
||||
let descriptionForItem: (Any) -> String = { item in
|
||||
var description = ""
|
||||
printFunction(item, &description)
|
||||
return description
|
||||
}
|
||||
|
||||
let bodyComponents = map { element in
|
||||
return descriptionForItem(element.key) + ": " + descriptionForItem(element.value)
|
||||
}
|
||||
|
||||
let body = bodyComponents.joined(separator: ", ")
|
||||
|
||||
return "[\(body)]"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//
|
||||
// OrderedDictionary.h
|
||||
// OrderedDictionary
|
||||
//
|
||||
// Created by Lukas Kubanek on 29/08/15.
|
||||
// Copyright © 2015 Lukas Kubanek. All rights reserved.
|
||||
//
|
||||
+576
-185
@@ -1,75 +1,213 @@
|
||||
//
|
||||
// OrderedDictionary.swift
|
||||
// OrderedDictionary
|
||||
//
|
||||
// Created by Lukas Kubanek on 29/08/15.
|
||||
// Copyright © 2015 Lukas Kubanek. All rights reserved.
|
||||
//
|
||||
/// A generic collection for storing key-value pairs in an ordered manner.
|
||||
///
|
||||
/// Same as in a dictionary all keys in the collection are unique and have an associated value.
|
||||
/// Same as in an array, all key-value pairs (elements) are kept sorted and accessible by
|
||||
/// a zero-based integer index.
|
||||
public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
|
||||
|
||||
public struct OrderedDictionary<Key: Hashable, Value>: MutableCollectionType {
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Type Aliases
|
||||
// ======================================================= //
|
||||
|
||||
public typealias Element = (Key, Value)
|
||||
/// The type of the key-value pair stored in the ordered dictionary.
|
||||
public typealias Element = (key: Key, value: Value)
|
||||
|
||||
/// The type of the index.
|
||||
public typealias Index = Int
|
||||
|
||||
/// The type of the indices collection.
|
||||
public typealias Indices = CountableRange<Int>
|
||||
|
||||
/// The type of the contiguous subrange of the ordered dictionary's elements.
|
||||
///
|
||||
/// - SeeAlso: OrderedDictionarySlice
|
||||
public typealias SubSequence = OrderedDictionarySlice<Key, Value>
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Initialization
|
||||
// ======================================================= //
|
||||
|
||||
/// Creates an empty ordered dictionary.
|
||||
public init() {}
|
||||
|
||||
public init(elements: [Element]) {
|
||||
/// 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) })
|
||||
}
|
||||
|
||||
/// 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) })
|
||||
}
|
||||
|
||||
/// Creates an ordered dictionary from a regular unsorted dictionary by sorting it using the
|
||||
/// 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) throws -> Bool
|
||||
) rethrows {
|
||||
let elements = try unsorted
|
||||
.map { (key: $0.key, value: $0.value) }
|
||||
.sorted(by: areInIncreasingOrder)
|
||||
|
||||
self.init(elements)
|
||||
}
|
||||
|
||||
/// Creates an ordered dictionary from a sequence of key-value pairs.
|
||||
///
|
||||
/// - 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")
|
||||
self[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Accessing Keys & Values
|
||||
// MARK: - Ordered Keys & Values
|
||||
// ======================================================= //
|
||||
|
||||
public var orderedKeys: [Key] {
|
||||
return _orderedKeys
|
||||
/// A collection containing just the keys of the ordered dictionary in the correct order.
|
||||
public var orderedKeys: OrderedDictionaryKeys<Key, Value> {
|
||||
return self.lazy.map { $0.key }
|
||||
}
|
||||
|
||||
public var orderedValues: [Value] {
|
||||
return _orderedKeys.flatMap { _keysToValues[$0] }
|
||||
/// A collection containing just the values of the ordered dictionary in the correct order.
|
||||
public var orderedValues: OrderedDictionaryValues<Key, Value> {
|
||||
return self.lazy.map { $0.value }
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Managing Content Using Keys
|
||||
// MARK: - Dictionary
|
||||
// ======================================================= //
|
||||
|
||||
/// Converts itself to a common unsorted dictionary.
|
||||
public var unorderedDictionary: Dictionary<Key, Value> {
|
||||
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
|
||||
// ======================================================= //
|
||||
|
||||
/// Accesses the value associated with the given key for reading and writing.
|
||||
///
|
||||
/// This key-based subscript returns the value for the given key if the key is found in the
|
||||
/// ordered dictionary, or `nil` if the key is not found.
|
||||
///
|
||||
/// When you assign a value for a key and that key already exists, the ordered dictionary
|
||||
/// overwrites the existing value and preservers the index of the key-value pair. If the ordered
|
||||
/// dictionary does not contain the key, a new key-value pair is appended to the end of the
|
||||
/// ordered dictionary.
|
||||
///
|
||||
/// If you assign `nil` as the value for the given key, the ordered dictionary removes that key
|
||||
/// and its associated value if it exists.
|
||||
///
|
||||
/// - Parameter key: The key to find in the ordered dictionary.
|
||||
/// - Returns: The value associated with `key` if `key` is in the ordered dictionary; otherwise,
|
||||
/// `nil`.
|
||||
public subscript(key: Key) -> Value? {
|
||||
get {
|
||||
return valueForKey(key)
|
||||
return value(forKey: key)
|
||||
}
|
||||
set(newValue) {
|
||||
if let newValue = newValue {
|
||||
updateValue(newValue, forKey: key)
|
||||
} else {
|
||||
removeValueForKey(key)
|
||||
removeValue(forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func containsKey(key: Key) -> Bool {
|
||||
return _orderedKeys.contains(key)
|
||||
/// Returns a Boolean value indicating whether the ordered dictionary contains the given key.
|
||||
///
|
||||
/// - 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 _keysToValues[key] != nil
|
||||
}
|
||||
|
||||
public func valueForKey(key: Key) -> Value? {
|
||||
/// Returns the value associated with the given key if the key is found in the ordered
|
||||
/// dictionary, or `nil` if the key is not found.
|
||||
///
|
||||
/// - Parameter key: The key to find in the ordered dictionary.
|
||||
/// - Returns: The value associated with `key` if `key` is in the ordered dictionary; otherwise,
|
||||
/// `nil`.
|
||||
public func value(forKey key: Key) -> Value? {
|
||||
return _keysToValues[key]
|
||||
}
|
||||
|
||||
public mutating func updateValue(value: Value, forKey key: Key) -> Value? {
|
||||
if _orderedKeys.contains(key) {
|
||||
guard let currentValue = _keysToValues[key] else {
|
||||
fatalError("Inconsistency error occured in OrderedDictionary")
|
||||
}
|
||||
/// Updates the value stored in the ordered dictionary for the given key, or appends a new
|
||||
/// 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
|
||||
/// 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 containsKey(key) {
|
||||
let currentValue = _unsafeValue(forKey: key)
|
||||
|
||||
_keysToValues[key] = value
|
||||
|
||||
@@ -82,205 +220,458 @@ public struct OrderedDictionary<Key: Hashable, Value>: MutableCollectionType {
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func removeValueForKey(key: Key) -> Value? {
|
||||
if let index = _orderedKeys.indexOf(key) {
|
||||
guard let currentValue = _keysToValues[key] else {
|
||||
fatalError("Inconsistency error occured in OrderedDictionary")
|
||||
}
|
||||
|
||||
_orderedKeys.removeAtIndex(index)
|
||||
_keysToValues[key] = nil
|
||||
|
||||
return currentValue
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func removeAll(keepCapacity keepCapacity: Bool = true) {
|
||||
_orderedKeys.removeAll(keepCapacity: keepCapacity)
|
||||
_keysToValues.removeAll(keepCapacity: keepCapacity)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Managing Content Using Indexes
|
||||
// ======================================================= //
|
||||
|
||||
public subscript(index: Index) -> Element {
|
||||
get {
|
||||
guard let element = elementAtIndex(index) else {
|
||||
fatalError("OrderedDictionary index out of range")
|
||||
}
|
||||
|
||||
return element
|
||||
}
|
||||
set(newValue) {
|
||||
updateElement(newValue, atIndex: index)
|
||||
}
|
||||
}
|
||||
|
||||
public func indexForKey(key: Key) -> Index? {
|
||||
return _orderedKeys.indexOf(key)
|
||||
}
|
||||
|
||||
public func elementAtIndex(index: Index) -> Element? {
|
||||
guard _orderedKeys.indices.contains(index) else { return nil }
|
||||
/// Removes the given key and its associated value from the ordered dictionary.
|
||||
///
|
||||
/// If the key is found in the ordered dictionary, this method returns the key's associated
|
||||
/// value. On removal, the indices of the ordered dictionary are invalidated. If the key is
|
||||
/// not found in the ordered dictionary, this method returns `nil`.
|
||||
///
|
||||
/// - Parameter key: The key to remove along with its associated value.
|
||||
/// - Returns: The value that was removed, or `nil` if the key was not present in the
|
||||
/// ordered dictionary.
|
||||
///
|
||||
/// - SeeAlso: remove(at:)
|
||||
@discardableResult
|
||||
public mutating func removeValue(forKey key: Key) -> Value? {
|
||||
guard let index = index(forKey: key) else { return nil }
|
||||
|
||||
let key = _orderedKeys[index]
|
||||
let currentValue = self[index].value
|
||||
|
||||
guard let value = self._keysToValues[key] else {
|
||||
fatalError("Inconsistency error occured in OrderedDictionary")
|
||||
}
|
||||
|
||||
return (key, value)
|
||||
}
|
||||
|
||||
public mutating func insertElementWithKey(key: Key, value: Value, atIndex index: Index) -> Value? {
|
||||
return insertElement((key, value), atIndex: index)
|
||||
}
|
||||
|
||||
public mutating func insertElement(newElement: Element, atIndex index: Index) -> Value? {
|
||||
guard index >= 0 else {
|
||||
fatalError("Negative OrderedDictionary index is out of range")
|
||||
}
|
||||
|
||||
guard index <= count else {
|
||||
fatalError("OrderedDictionary index out of range")
|
||||
}
|
||||
|
||||
let (key, value) = newElement
|
||||
|
||||
let adjustedIndex: Int
|
||||
let currentValue: Value?
|
||||
|
||||
if let currentIndex = _orderedKeys.indexOf(key) {
|
||||
currentValue = _keysToValues[key]
|
||||
adjustedIndex = (currentIndex < index - 1) ? index - 1 : index
|
||||
|
||||
_orderedKeys.removeAtIndex(currentIndex)
|
||||
_keysToValues[key] = nil
|
||||
} else {
|
||||
currentValue = nil
|
||||
adjustedIndex = index
|
||||
}
|
||||
|
||||
_orderedKeys.insert(key, atIndex: adjustedIndex)
|
||||
_keysToValues[key] = value
|
||||
_orderedKeys.remove(at: index)
|
||||
_keysToValues[key] = nil
|
||||
|
||||
return currentValue
|
||||
}
|
||||
|
||||
public mutating func updateElement(element: Element, atIndex index: Index) -> Element? {
|
||||
guard let currentElement = elementAtIndex(index) else {
|
||||
fatalError("OrderedDictionary index out of range")
|
||||
/// Removes all key-value pairs from the ordered dictionary and invalidates all indices.
|
||||
///
|
||||
/// - Parameter keepCapacity: Whether the ordered dictionary should keep its underlying storage.
|
||||
/// If you pass `true`, the operation preserves the storage capacity that the collection has,
|
||||
/// otherwise the underlying storage is released. The default is `false`.
|
||||
public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
|
||||
_orderedKeys.removeAll(keepingCapacity: keepCapacity)
|
||||
_keysToValues.removeAll(keepingCapacity: keepCapacity)
|
||||
}
|
||||
|
||||
private func _unsafeValue(forKey key: Key) -> Value {
|
||||
let value = _keysToValues[key]
|
||||
precondition(value != nil, "Inconsistency error occurred in OrderedDictionary")
|
||||
return value!
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Index-based Access
|
||||
// ======================================================= //
|
||||
|
||||
/// Accesses the key-value pair at the specified position.
|
||||
///
|
||||
/// The specified position has to be a valid index of the ordered dictionary. The index-base
|
||||
/// subscript returns the key-value pair corresponding to the index.
|
||||
///
|
||||
/// - Parameter position: The position of the key-value pair to access. `position` must be
|
||||
/// a valid index of the ordered dictionary and not equal to `endIndex`.
|
||||
/// - Returns: A tuple containing the key-value pair corresponding to `position`.
|
||||
///
|
||||
/// - SeeAlso: update(:at:)
|
||||
public subscript(position: Index) -> Element {
|
||||
precondition(indices.contains(position), "OrderedDictionary index is out of range")
|
||||
|
||||
let key = _orderedKeys[position]
|
||||
let value = _unsafeValue(forKey: key)
|
||||
|
||||
return (key, value)
|
||||
}
|
||||
|
||||
/// Returns the index for the given key.
|
||||
///
|
||||
/// - Parameter key: The key to find in the ordered dictionary.
|
||||
/// - 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? {
|
||||
return _orderedKeys.index(of: key)
|
||||
}
|
||||
|
||||
/// Returns the key-value pair at the specified index, or `nil` if there is no key-value pair
|
||||
/// at that index.
|
||||
///
|
||||
/// - Parameter index: The index of the key-value pair to be looked up. `index` does not have to
|
||||
/// be a valid index.
|
||||
/// - Returns: A tuple containing the key-value pair corresponding to `index` if the index is
|
||||
/// valid; otherwise, `nil`.
|
||||
public func elementAt(_ index: Index) -> Element? {
|
||||
return indices.contains(index) ? self[index] : nil
|
||||
}
|
||||
|
||||
/// Checks whether the given key-value pair can be inserted into to ordered dictionary by
|
||||
/// validating the presence of the key.
|
||||
///
|
||||
/// - Parameter newElement: The key-value pair to be inserted into the ordered dictionary.
|
||||
/// - Returns: `true` if the key-value pair can be safely inserted; otherwise, `false`.
|
||||
///
|
||||
/// - SeeAlso: canInsert(key:)
|
||||
/// - SeeAlso: canInsert(at:)
|
||||
@available(*, deprecated, message: "Use canInsert(key:) with the element's key instead")
|
||||
public func canInsert(_ newElement: Element) -> Bool {
|
||||
return canInsert(key: newElement.key)
|
||||
}
|
||||
|
||||
/// Checks whether a key-value pair with the given key can be inserted into the ordered
|
||||
/// dictionary by validating its presence.
|
||||
///
|
||||
/// - Parameter key: The key to be inserted into the ordered dictionary.
|
||||
/// - Returns: `true` if the key can safely be inserted; ortherwise, `false`.
|
||||
///
|
||||
/// - SeeAlso: canInsert(at:)
|
||||
public func canInsert(key: Key) -> Bool {
|
||||
return !containsKey(key)
|
||||
}
|
||||
|
||||
/// Checks whether a new key-value pair can be inserted into the ordered dictionary at the
|
||||
/// given index.
|
||||
///
|
||||
/// - Parameter index: The index the new key-value pair should be inserted at.
|
||||
/// - Returns: `true` if a new key-value pair can be inserted at the specified index; otherwise,
|
||||
/// `false`.
|
||||
///
|
||||
/// - SeeAlso: canInsert(key:)
|
||||
public func canInsert(at index: Index) -> Bool {
|
||||
return index >= startIndex && index <= endIndex
|
||||
}
|
||||
|
||||
/// Inserts a new key-value pair at the specified position.
|
||||
///
|
||||
/// If the key of the inserted pair already exists in the ordered dictionary, a runtime error
|
||||
/// is triggered. Use `canInsert(_:)` for performing a check first, so that this method can
|
||||
/// be executed safely.
|
||||
///
|
||||
/// - Parameter newElement: The new key-value pair to insert into the ordered dictionary. The
|
||||
/// key contained in the pair must not be already present in the ordered dictionary.
|
||||
/// - Parameter index: The position at which to insert the new key-value pair. `index` must be
|
||||
/// a valid index of the ordered dictionary or equal to `endIndex` property.
|
||||
///
|
||||
/// - SeeAlso: canInsert(key:)
|
||||
/// - SeeAlso: canInsert(at:)
|
||||
/// - SeeAlso: update(:at:)
|
||||
public mutating func insert(_ newElement: Element, at index: Index) {
|
||||
precondition(canInsert(key: newElement.key), "Cannot insert duplicate key in OrderedDictionary")
|
||||
precondition(canInsert(at: index), "Cannot insert at invalid index in OrderedDictionary")
|
||||
|
||||
let (key, value) = newElement
|
||||
|
||||
_orderedKeys.insert(key, at: index)
|
||||
_keysToValues[key] = value
|
||||
}
|
||||
|
||||
/// Checks whether the key-value pair at the given index can be updated with the given key-value
|
||||
/// pair. This is not the case if the key of the updated element is already present in the
|
||||
/// ordered dictionary and located at another index than the updated one.
|
||||
///
|
||||
/// Although this is a checking method, a valid index has to be provided.
|
||||
///
|
||||
/// - Parameter newElement: The key-value pair to be set at the specified position.
|
||||
/// - Parameter index: The position at which to set the key-value pair. `index` must be a valid
|
||||
/// index of the ordered dictionary.
|
||||
public func canUpdate(_ newElement: Element, at index: Index) -> Bool {
|
||||
var keyPresentAtIndex = false
|
||||
return _canUpdate(newElement, at: index, keyPresentAtIndex: &keyPresentAtIndex)
|
||||
}
|
||||
|
||||
/// Updates the key-value pair located at the specified position.
|
||||
///
|
||||
/// If the key of the updated pair already exists in the ordered dictionary *and* is located at
|
||||
/// a different position than the specified one, a runtime error is triggered. Use
|
||||
/// `canUpdate(_:at:)` for performing a check first, so that this method can be executed safely.
|
||||
///
|
||||
/// - Parameter newElement: The key-value pair to be set at the specified position.
|
||||
/// - Parameter index: The position at which to set the key-value pair. `index` must be a valid
|
||||
/// index of the ordered dictionary.
|
||||
///
|
||||
/// - SeeAlso: canUpdate(_:at:)
|
||||
/// - SeeAlso: insert(:at:)
|
||||
@discardableResult
|
||||
public mutating func update(_ newElement: Element, at index: Index) -> Element? {
|
||||
// Store the flag indicating whether the key of the inserted element
|
||||
// is present at the updated index
|
||||
var keyPresentAtIndex = false
|
||||
|
||||
precondition(
|
||||
_canUpdate(newElement, at: index, keyPresentAtIndex: &keyPresentAtIndex),
|
||||
"OrderedDictionary update duplicates key"
|
||||
)
|
||||
|
||||
// Decompose the element
|
||||
let (key, value) = newElement
|
||||
|
||||
// Load the current element at the index
|
||||
let replacedElement = self[index]
|
||||
|
||||
// If its key differs, remove its associated value
|
||||
if (!keyPresentAtIndex) {
|
||||
_keysToValues.removeValue(forKey: replacedElement.key)
|
||||
}
|
||||
|
||||
let (newKey, newValue) = element
|
||||
// Store the new position of the key and the new value associated with the key
|
||||
_orderedKeys[index] = key
|
||||
_keysToValues[key] = value
|
||||
|
||||
_orderedKeys[index] = newKey
|
||||
_keysToValues[newKey] = newValue
|
||||
return replacedElement
|
||||
}
|
||||
|
||||
/// Removes and returns the key-value pair at the specified position if there is any key-value
|
||||
/// pair, or `nil` if there is none.
|
||||
///
|
||||
/// - Parameter index: The position of the key-value pair to remove.
|
||||
/// - Returns: The element at the specified index, or `nil` if the position is not taken.
|
||||
///
|
||||
/// - SeeAlso: removeValue(forKey:)
|
||||
@discardableResult
|
||||
public mutating func remove(at index: Index) -> Element? {
|
||||
guard let element = elementAt(index) else { return nil }
|
||||
|
||||
return currentElement
|
||||
_orderedKeys.remove(at: index)
|
||||
_keysToValues.removeValue(forKey: element.key)
|
||||
|
||||
return element
|
||||
}
|
||||
|
||||
public mutating func removeAtIndex(index: Index) -> Element? {
|
||||
if let element = elementAtIndex(index) {
|
||||
_orderedKeys.removeAtIndex(index)
|
||||
_keysToValues.removeValueForKey(element.0)
|
||||
|
||||
return element
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
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)
|
||||
|
||||
let keyNotPresent = currentIndexOfKey == nil
|
||||
keyPresentAtIndex = currentIndexOfKey == index
|
||||
|
||||
return keyNotPresent || keyPresentAtIndex
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - CollectionType Conformance
|
||||
// MARK: - Removing First & Last Elements
|
||||
// ======================================================= //
|
||||
|
||||
public var startIndex: Index {
|
||||
return _orderedKeys.startIndex
|
||||
/// 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)
|
||||
}
|
||||
|
||||
public var endIndex: Index {
|
||||
return _orderedKeys.endIndex
|
||||
/// 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: - Internal Backing Store
|
||||
// MARK: - Moving Elements
|
||||
// ======================================================= //
|
||||
|
||||
/// The backing store for the ordered keys.
|
||||
private var _orderedKeys = [Key]()
|
||||
/// Moves an existing key-value pair specified by the given key to the new index by removing it
|
||||
/// from its original index first and inserting it at the new index. If the movement is
|
||||
/// actually performed, the previous index of the key-value pair is returned. Otherwise, `nil`
|
||||
/// is returned.
|
||||
///
|
||||
/// - Parameter key: The key specifying the key-value pair to move.
|
||||
/// - Parameter newIndex: The new index the key-value pair should be moved to.
|
||||
/// - Returns: The previous index of the key-value pair if it was sucessfully moved.
|
||||
@discardableResult
|
||||
public mutating func moveElement(forKey key: Key, to newIndex: Index) -> Index? {
|
||||
// Load the previous index and return nil if the index is not found.
|
||||
guard let previousIndex = index(forKey: key) else { return nil }
|
||||
|
||||
// If the previous and new indices match, threat it as if the movement was already
|
||||
// performed.
|
||||
guard previousIndex != newIndex else { return previousIndex }
|
||||
|
||||
// Remove the value for the key at its original index.
|
||||
let value = removeValue(forKey: key)!
|
||||
|
||||
// Validate the new index.
|
||||
precondition(canInsert(at: newIndex), "Cannot move to invalid index in OrderedDictionary")
|
||||
|
||||
// Insert the element at the new index.
|
||||
insert((key: key, value: value), at: newIndex)
|
||||
|
||||
return previousIndex
|
||||
}
|
||||
|
||||
/// The backing store for the mapping of keys to values.
|
||||
private var _keysToValues = [Key: Value]()
|
||||
// ======================================================= //
|
||||
// MARK: - Sorting Elements
|
||||
// ======================================================= //
|
||||
|
||||
/// Sorts the ordered dictionary in place, using the given predicate as the comparison between
|
||||
/// elements.
|
||||
///
|
||||
/// The predicate must be a *strict weak ordering* over the elements.
|
||||
///
|
||||
/// - Parameter areInIncreasingOrder: A predicate that returns `true` if its first argument
|
||||
/// should be ordered before its second argument; otherwise, `false`.
|
||||
///
|
||||
/// - SeeAlso: MutableCollection.sort(by:), sorted(by:)
|
||||
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
|
||||
/// elements.
|
||||
///
|
||||
/// The predicate must be a *strict weak ordering* over the elements.
|
||||
///
|
||||
/// - Parameter areInIncreasingOrder: A predicate that returns `true` if its first argument
|
||||
/// should be ordered before its second argument; otherwise, `false`.
|
||||
/// - Returns: A new ordered dictionary sorted according to the predicate.
|
||||
///
|
||||
/// - SeeAlso: MutableCollection.sorted(by:), sort(by:)
|
||||
/// - MutatingVariant: sort
|
||||
public func sorted(
|
||||
by areInIncreasingOrder: (Element, Element) throws -> Bool
|
||||
) rethrows -> OrderedDictionary<Key, Value> {
|
||||
return OrderedDictionary(try _sortedElements(by: areInIncreasingOrder))
|
||||
}
|
||||
|
||||
private func _sortedElements(
|
||||
by areInIncreasingOrder: (Element, Element) throws -> Bool
|
||||
) rethrows -> [Element] {
|
||||
return try sorted(by: areInIncreasingOrder)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Internal Storage
|
||||
// ======================================================= //
|
||||
|
||||
/// The backing storage for the ordered keys.
|
||||
fileprivate var _orderedKeys = [Key]()
|
||||
|
||||
/// The backing storage for the mapping of keys to values.
|
||||
fileprivate var _keysToValues = [Key: Value]()
|
||||
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Initializations from Literals
|
||||
// MARK: - Subtypes
|
||||
// ======================================================= //
|
||||
|
||||
extension OrderedDictionary: ArrayLiteralConvertible {
|
||||
#if swift(>=4.1)
|
||||
|
||||
/// A view into an ordered dictionary whose indices are a subrange of the indices of the ordered
|
||||
/// dictionary.
|
||||
public typealias OrderedDictionarySlice<Key: Hashable, Value> = Slice<OrderedDictionary<Key, Value>>
|
||||
|
||||
/// A collection containing the keys of the ordered dictionary.
|
||||
///
|
||||
/// Under the hood this is a lazily evaluated bidirectional collection deriving the keys from
|
||||
/// the base ordered dictionary on-the-fly.
|
||||
public typealias OrderedDictionaryKeys<Key: Hashable, Value> = LazyMapCollection<OrderedDictionary<Key, Value>, Key>
|
||||
|
||||
/// A collection containing the values of the ordered dictionary.
|
||||
///
|
||||
/// Under the hood this is a lazily evaluated bidirectional collection deriving the values from
|
||||
/// the base ordered dictionary on-the-fly.
|
||||
public typealias OrderedDictionaryValues<Key: Hashable, Value> = LazyMapCollection<OrderedDictionary<Key, Value>, Value>
|
||||
|
||||
#else
|
||||
|
||||
/// A view into an ordered dictionary whose indices are a subrange of the indices of the ordered
|
||||
/// dictionary.
|
||||
public typealias OrderedDictionarySlice<Key: Hashable, Value> = BidirectionalSlice<OrderedDictionary<Key, Value>>
|
||||
|
||||
/// A collection containing the keys of the ordered dictionary.
|
||||
///
|
||||
/// Under the hood this is a lazily evaluated bidirectional collection deriving the keys from
|
||||
/// the base ordered dictionary on-the-fly.
|
||||
public typealias OrderedDictionaryKeys<Key: Hashable, Value> = LazyMapBidirectionalCollection<OrderedDictionary<Key, Value>, Key>
|
||||
|
||||
/// A collection containing the values of the ordered dictionary.
|
||||
///
|
||||
/// Under the hood this is a lazily evaluated bidirectional collection deriving the values from
|
||||
/// the base ordered dictionary on-the-fly.
|
||||
public typealias OrderedDictionaryValues<Key: Hashable, Value> = LazyMapBidirectionalCollection<OrderedDictionary<Key, Value>, Value>
|
||||
|
||||
#endif
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Literals
|
||||
// ======================================================= //
|
||||
|
||||
extension OrderedDictionary: ExpressibleByArrayLiteral {
|
||||
|
||||
/// Creates an ordered dictionary initialized from an array literal containing a list of
|
||||
/// key-value pairs.
|
||||
public init(arrayLiteral elements: Element...) {
|
||||
self.init(elements: elements)
|
||||
self.init(elements)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension OrderedDictionary: DictionaryLiteralConvertible {
|
||||
extension OrderedDictionary: ExpressibleByDictionaryLiteral {
|
||||
|
||||
public init(dictionaryLiteral elements: Element...) {
|
||||
self.init(elements: elements)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Description
|
||||
// ======================================================= //
|
||||
|
||||
extension OrderedDictionary: CustomStringConvertible, CustomDebugStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
return constructDescription(debug: false)
|
||||
}
|
||||
|
||||
public var debugDescription: String {
|
||||
return constructDescription(debug: true)
|
||||
}
|
||||
|
||||
private func constructDescription(debug debug: Bool) -> String {
|
||||
// The implementation of the description is inspired by zwaldowski's implementation of the ordered dictionary.
|
||||
// See http://bit.ly/1VL4JUR
|
||||
|
||||
if isEmpty { return "[:]" }
|
||||
|
||||
func descriptionForItem(item: Any) -> String {
|
||||
var description = ""
|
||||
|
||||
if debug {
|
||||
debugPrint(item, separator: "", terminator: "", toStream: &description)
|
||||
} else {
|
||||
print(item, separator: "", terminator: "", toStream: &description)
|
||||
}
|
||||
|
||||
return description
|
||||
}
|
||||
|
||||
let bodyComponents = map({ (key: Key, value: Value) -> String in
|
||||
return descriptionForItem(key) + ": " + descriptionForItem(value)
|
||||
/// Creates an ordered dictionary initialized from a dictionary literal.
|
||||
public init(dictionaryLiteral elements: (Key, Value)...) {
|
||||
self.init(elements.map { element in
|
||||
let (key, value) = element
|
||||
return (key: key, value: value)
|
||||
})
|
||||
|
||||
let body = bodyComponents.joinWithSeparator(", ")
|
||||
|
||||
return "[\(body)]"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public func == <Key: Equatable, Value: Equatable>(lhs: OrderedDictionary<Key, Value>, rhs: OrderedDictionary<Key, Value>) -> Bool {
|
||||
return lhs._orderedKeys == rhs._orderedKeys && lhs._keysToValues == rhs._keysToValues
|
||||
// ======================================================= //
|
||||
// MARK: - Equatable Conformance
|
||||
// ======================================================= //
|
||||
|
||||
#if swift(>=4.1)
|
||||
|
||||
extension OrderedDictionary: Equatable where Value: Equatable {}
|
||||
|
||||
#endif
|
||||
|
||||
extension OrderedDictionary where Value: Equatable {
|
||||
|
||||
/// Returns a Boolean value that indicates whether the two given ordered dictionaries with
|
||||
/// equatable values are equal.
|
||||
public static func == (lhs: OrderedDictionary, rhs: OrderedDictionary) -> Bool {
|
||||
return lhs._orderedKeys == rhs._orderedKeys
|
||||
&& lhs._keysToValues == rhs._keysToValues
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// 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>0.5</string>
|
||||
<string>2.2.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2015 Lukas Kubanek. All rights reserved.</string>
|
||||
<string>Copyright © 2015-2019 Lukas Kubanek. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
|
||||
+473
-150
@@ -1,13 +1,33 @@
|
||||
//
|
||||
// OrderedDictionaryTests.swift
|
||||
// OrderedDictionaryTests
|
||||
//
|
||||
// Created by Lukas Kubanek on 29/08/15.
|
||||
// Copyright © 2015 Lukas Kubanek. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import OrderedDictionary
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
#if !swift(>=4.1)
|
||||
|
||||
/// This is a shim for testing the equality in Swift <4.1.
|
||||
public func XCTAssertEqual<K, V: Equatable>(
|
||||
_ expression1: OrderedDictionary<K, V>,
|
||||
_ expression2: OrderedDictionary<K, V>,
|
||||
_ message: @autoclosure () -> String = "",
|
||||
file: StaticString = #file,
|
||||
line: UInt = #line
|
||||
) {
|
||||
return XCTAssertTrue(
|
||||
expression1 == expression2,
|
||||
message,
|
||||
file: file,
|
||||
line: line
|
||||
)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct TestValue: Equatable {
|
||||
var string: String
|
||||
static func == (lhs: TestValue, rhs: TestValue) -> Bool {
|
||||
return lhs.string == rhs.string
|
||||
}
|
||||
}
|
||||
|
||||
class OrderedDictionaryTests: XCTestCase {
|
||||
|
||||
@@ -16,46 +36,112 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
// ======================================================= //
|
||||
|
||||
func testInitializationUsingArrayLiteral() {
|
||||
let expected = OrderedDictionary<String, Int>(elements: [("A", 1), ("B", 2), ("C", 3)])
|
||||
let actual: OrderedDictionary<String, Int> = [("A", 1), ("B", 2), ("C", 3)]
|
||||
let actual: OrderedDictionary<String, Int> = [
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("C", 3)
|
||||
]
|
||||
|
||||
XCTAssertTrue(expected == actual)
|
||||
let expected = OrderedDictionary<String, Int>([
|
||||
(key: "A", value: 1),
|
||||
(key: "B", value: 2),
|
||||
(key: "C", value: 3)
|
||||
])
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testInitializationUsingDictionaryLiteral() {
|
||||
let expected = OrderedDictionary<String, Int>(elements: [("A", 1), ("B", 2), ("C", 3)])
|
||||
let actual: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let actual: OrderedDictionary<String, Int> = [
|
||||
"A": 1,
|
||||
"B": 2,
|
||||
"C": 3
|
||||
]
|
||||
|
||||
XCTAssertTrue(expected == actual)
|
||||
let expected = OrderedDictionary<String, Int>([
|
||||
(key: "A", value: 1),
|
||||
(key: "B", value: 2),
|
||||
(key: "C", value: 3)
|
||||
])
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Description
|
||||
// ======================================================= //
|
||||
|
||||
struct DescribedValue: CustomStringConvertible, CustomDebugStringConvertible {
|
||||
init(_ value: Int) { self.value = value }
|
||||
let value: Int
|
||||
var description: String { return "\(value)" }
|
||||
var debugDescription: String { return "debug(\(value))" }
|
||||
func testInitializationUsingValuesAndKeyProviderClosure() {
|
||||
let actual = OrderedDictionary(
|
||||
values: [1, 2, 3],
|
||||
keyedBy: { "\($0)" }
|
||||
)
|
||||
|
||||
let expected = OrderedDictionary<String, Int>([
|
||||
(key: "1", value: 1),
|
||||
(key: "2", value: 2),
|
||||
(key: "3", value: 3)
|
||||
])
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testDescription() {
|
||||
let expected = "[A: 1, B: 2, C: 3]"
|
||||
func testInitializationUsingValuesAnyKeyPath() {
|
||||
let actual = OrderedDictionary(
|
||||
values: [
|
||||
TestValue(string: "A"),
|
||||
TestValue(string: "B"),
|
||||
TestValue(string: "C")
|
||||
],
|
||||
keyedBy: \.string
|
||||
)
|
||||
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = ["A": DescribedValue(1), "B": DescribedValue(2), "C": DescribedValue(3)]
|
||||
let actual = orderedDictionary.description
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
let expected = OrderedDictionary<String, TestValue>([
|
||||
(key: "A", value: TestValue(string: "A")),
|
||||
(key: "B", value: TestValue(string: "B")),
|
||||
(key: "C", value: TestValue(string: "C"))
|
||||
])
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testDebugDescription() {
|
||||
let expected = "[\"A\": debug(1), \"B\": debug(2), \"C\": debug(3)]"
|
||||
func testInitializationUsingUnsortedDictionaryAndSortFunction() {
|
||||
let actual = OrderedDictionary(
|
||||
unsorted: [
|
||||
2: "foo",
|
||||
1: "bar",
|
||||
4: "baz",
|
||||
5: "bat",
|
||||
3: "bam"
|
||||
],
|
||||
areInIncreasingOrder: { $0.key < $1.key }
|
||||
)
|
||||
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = ["A": DescribedValue(1), "B": DescribedValue(2), "C": DescribedValue(3)]
|
||||
let actual = orderedDictionary.debugDescription
|
||||
let expected = OrderedDictionary([
|
||||
(key: 1, value: "bar"),
|
||||
(key: 2, value: "foo"),
|
||||
(key: 3, value: "bam"),
|
||||
(key: 4, value: "baz"),
|
||||
(key: 5, value: "bat")
|
||||
])
|
||||
|
||||
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([
|
||||
(key: 1, value: "bar"),
|
||||
(key: 2, value: "foo"),
|
||||
(key: 3, value: "bam"),
|
||||
(key: 4, value: "baz"),
|
||||
(key: 5, value: "bat")
|
||||
])
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -68,63 +154,72 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
|
||||
XCTAssertEqual(orderedDictionary["A"], 1)
|
||||
XCTAssertEqual(orderedDictionary.valueForKey("A"), 1)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("A"), 0)
|
||||
XCTAssertEqual(orderedDictionary.value(forKey: "A"), 1)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "A"), 0)
|
||||
XCTAssertTrue(orderedDictionary.containsKey("A"))
|
||||
XCTAssertTrue(orderedDictionary[0] == ("A", 1))
|
||||
|
||||
XCTAssertEqual(orderedDictionary["B"], 2)
|
||||
XCTAssertEqual(orderedDictionary.valueForKey("B"), 2)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("B"), 1)
|
||||
XCTAssertEqual(orderedDictionary.value(forKey: "B"), 2)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "B"), 1)
|
||||
XCTAssertTrue(orderedDictionary.containsKey("B"))
|
||||
XCTAssertTrue(orderedDictionary[1] == ("B", 2))
|
||||
|
||||
XCTAssertEqual(orderedDictionary["C"], 3)
|
||||
XCTAssertEqual(orderedDictionary.valueForKey("C"), 3)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("C"), 2)
|
||||
XCTAssertEqual(orderedDictionary.value(forKey: "C"), 3)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "C"), 2)
|
||||
XCTAssertTrue(orderedDictionary.containsKey("C"))
|
||||
XCTAssertTrue(orderedDictionary[2] == ("C", 3))
|
||||
}
|
||||
|
||||
func testGenerator() {
|
||||
func testCreatingIterator() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
var generator = orderedDictionary.generate()
|
||||
var iterator = orderedDictionary.makeIterator()
|
||||
|
||||
let indexes = [0, 1, 2]
|
||||
var indexesGenerator = indexes.generate()
|
||||
var indexesIterator = indexes.makeIterator()
|
||||
|
||||
while let (actualKey, actualValue) = generator.next() {
|
||||
let index = indexesGenerator.next()
|
||||
while let (actualKey, actualValue) = iterator.next() {
|
||||
let index = indexesIterator.next()
|
||||
let (expectedKey, expectedValue) = orderedDictionary[index!]
|
||||
|
||||
XCTAssertEqual(expectedKey, actualKey)
|
||||
XCTAssertEqual(expectedValue, actualValue)
|
||||
XCTAssertEqual(actualKey, expectedKey)
|
||||
XCTAssertEqual(actualValue, expectedValue)
|
||||
}
|
||||
|
||||
XCTAssertNil(generator.next())
|
||||
XCTAssertNil(indexesGenerator.next())
|
||||
XCTAssertNil(iterator.next())
|
||||
XCTAssertNil(indexesIterator.next())
|
||||
}
|
||||
|
||||
func testOrderedKeys() {
|
||||
func testAccessingOrderedKeys() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let actual = Array(orderedDictionary.orderedKeys)
|
||||
|
||||
let expected = ["A", "B", "C"]
|
||||
let actual = orderedDictionary.orderedKeys
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testOrderedValues() {
|
||||
func testAccessingOrderedValues() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let actual = Array(orderedDictionary.orderedValues)
|
||||
|
||||
let expected = [1, 2, 3]
|
||||
let actual = orderedDictionary.orderedValues
|
||||
|
||||
XCTAssertEqual(expected, actual)
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testAccessingUnsortedDictionary() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let actual = orderedDictionary.unorderedDictionary
|
||||
|
||||
let expected = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Content Modifications
|
||||
// MARK: - Key-based Modifications
|
||||
// ======================================================= //
|
||||
|
||||
func testKeyBasedModifications() {
|
||||
@@ -137,89 +232,103 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
|
||||
XCTAssertEqual(orderedDictionary["A"], 5)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("A"), 0)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "A"), 0)
|
||||
XCTAssertTrue(orderedDictionary.containsKey("A"))
|
||||
|
||||
XCTAssertNil(orderedDictionary["B"])
|
||||
XCTAssertNil(orderedDictionary.indexForKey("B"))
|
||||
XCTAssertNil(orderedDictionary.index(forKey: "B"))
|
||||
XCTAssertFalse(orderedDictionary.containsKey("B"))
|
||||
|
||||
XCTAssertEqual(orderedDictionary["C"], 3)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("C"), 1)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "C"), 1)
|
||||
XCTAssertTrue(orderedDictionary.containsKey("C"))
|
||||
|
||||
XCTAssertEqual(orderedDictionary["D"], 10)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("D"), 2)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "D"), 2)
|
||||
XCTAssertTrue(orderedDictionary.containsKey("D"))
|
||||
}
|
||||
|
||||
func testIndexBasedModifications() {
|
||||
// ======================================================= //
|
||||
// MARK: - Index-based Insertions
|
||||
// ======================================================= //
|
||||
|
||||
func testIndexBasedInsertionsWithUniqueKeys() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
orderedDictionary.insert((key: "T", value: 15), at: 0)
|
||||
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 actual = orderedDictionary
|
||||
|
||||
orderedDictionary[0] = ("F", 10)
|
||||
orderedDictionary[1] = ("B", 5)
|
||||
let expected: OrderedDictionary<String, Int> = ["T": 15, "A": 1, "W": 18, "U": 16, "B": 2, "C": 3, "V": 17]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionWithDuplicateKey() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let invalidKey = "A"
|
||||
|
||||
XCTAssertFalse(orderedDictionary.canInsert(key: invalidKey))
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionWithNegativeIndex() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let invalidIndex = -1
|
||||
|
||||
XCTAssertFalse(orderedDictionary.canInsert(at: invalidIndex))
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionWithIndexOutOfBounds() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let invalidIndex = 4
|
||||
|
||||
XCTAssertFalse(orderedDictionary.canInsert(at: invalidIndex))
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Index-based Updates
|
||||
// ======================================================= //
|
||||
|
||||
func testIndexBasedUpdateMethodWithNewUniqueKey() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let previousElement = orderedDictionary.update((key: "D", value: 4), at: 1)
|
||||
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
XCTAssertTrue(orderedDictionary[0] == ("F", 10))
|
||||
XCTAssertTrue(orderedDictionary[1] == ("B", 5))
|
||||
XCTAssertTrue(orderedDictionary[2] == ("C", 3))
|
||||
XCTAssertTrue(previousElement! == ("B", 2))
|
||||
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "D": 4, "C": 3]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testIndexBasedUpdateMethodByReplacingSameKey() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let previousElement = orderedDictionary.update((key: "B", value: 42), at: 1)
|
||||
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
XCTAssertTrue(previousElement! == ("B", 2))
|
||||
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "B": 42, "C": 3]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testIndexBasedUpdateMethodByDuplicatingKey() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
let element = (key: "A", value: 42)
|
||||
|
||||
XCTAssertTrue(orderedDictionary.canUpdate(element, at: 0))
|
||||
XCTAssertFalse(orderedDictionary.canUpdate(element, at: 1))
|
||||
XCTAssertFalse(orderedDictionary.canUpdate(element, at: 2))
|
||||
}
|
||||
|
||||
func testRetrievingElementAtNonExistentIndex() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
XCTAssertNil(orderedDictionary.elementAtIndex(42))
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionsOfElementsWithDistinctKeys() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
orderedDictionary.insertElement(("T", 15), atIndex: 0)
|
||||
orderedDictionary.insertElement(("U", 16), atIndex: 2)
|
||||
orderedDictionary.insertElement(("V", 17), atIndex: 5)
|
||||
orderedDictionary.insertElement(("W", 18), atIndex: 2)
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["T": 15, "A": 1, "W": 18, "U": 16, "B": 2, "C": 3, "V": 17]
|
||||
let actual = orderedDictionary
|
||||
|
||||
XCTAssertTrue(expected == actual)
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionOfElementWithSameKeyBeforeItsCurrentIndex() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let previousValue = orderedDictionary.insertElement(("B", 5), atIndex: 0)
|
||||
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
XCTAssertEqual(previousValue, 2)
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["B": 5, "A": 1, "C": 3]
|
||||
let actual = orderedDictionary
|
||||
|
||||
XCTAssertTrue(expected == actual)
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionOfElementWithSameKeyAtItsCurrentIndex() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let previousValue = orderedDictionary.insertElement(("B", 5), atIndex: 1)
|
||||
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
XCTAssertEqual(previousValue, 2)
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "B": 5, "C": 3]
|
||||
let actual = orderedDictionary
|
||||
|
||||
XCTAssertTrue(expected == actual)
|
||||
}
|
||||
|
||||
func testIndexBasedInsertionOfElementWithSameKeyAfterItsCurrentIndex() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
let previousValue = orderedDictionary.insertElement(("B", 5), atIndex: 3)
|
||||
|
||||
XCTAssertEqual(orderedDictionary.count, 3)
|
||||
XCTAssertEqual(previousValue, 2)
|
||||
|
||||
let expected: OrderedDictionary<String, Int> = ["A": 1, "C": 3, "B": 5]
|
||||
let actual = orderedDictionary
|
||||
|
||||
XCTAssertTrue(expected == actual)
|
||||
XCTAssertNil(orderedDictionary.elementAt(42))
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
@@ -237,8 +346,8 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
func testKeyBasedRemoval() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3]
|
||||
|
||||
let removedValue1 = orderedDictionary.removeValueForKey("A")
|
||||
let removedValue2 = orderedDictionary.removeValueForKey("K")
|
||||
let removedValue1 = orderedDictionary.removeValue(forKey: "A")
|
||||
let removedValue2 = orderedDictionary.removeValue(forKey: "K")
|
||||
|
||||
XCTAssertEqual(removedValue1, 1)
|
||||
XCTAssertNil(removedValue2)
|
||||
@@ -246,62 +355,276 @@ class OrderedDictionaryTests: XCTestCase {
|
||||
XCTAssertEqual(orderedDictionary.count, 2)
|
||||
|
||||
XCTAssertNil(orderedDictionary["A"])
|
||||
XCTAssertNil(orderedDictionary.indexForKey("A"))
|
||||
XCTAssertNil(orderedDictionary.index(forKey: "A"))
|
||||
|
||||
XCTAssertEqual(orderedDictionary["B"], 2)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("B"), 0)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "B"), 0)
|
||||
|
||||
XCTAssertEqual(orderedDictionary["C"], 3)
|
||||
XCTAssertEqual(orderedDictionary.indexForKey("C"), 1)
|
||||
XCTAssertEqual(orderedDictionary.index(forKey: "C"), 1)
|
||||
}
|
||||
|
||||
func testIndexBasedRemoval() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
let (actualKey1, actualValue1) = orderedDictionary.remove(at: 0)!
|
||||
let (expectedKey1, expectedValue1) = ("A", 1)
|
||||
let (actualKey1, actualValue1) = orderedDictionary.removeAtIndex(0)!
|
||||
|
||||
XCTAssertEqual(expectedKey1, actualKey1)
|
||||
XCTAssertEqual(expectedValue1, actualValue1)
|
||||
XCTAssertEqual(actualKey1, expectedKey1)
|
||||
XCTAssertEqual(actualValue1, expectedValue1)
|
||||
|
||||
let (actualKey2, actualValue2) = orderedDictionary.remove(at: 2)!
|
||||
let (expectedKey2, expectedValue2) = ("D", 4)
|
||||
let (actualKey2, actualValue2) = orderedDictionary.removeAtIndex(2)!
|
||||
|
||||
XCTAssertEqual(expectedKey2, actualKey2)
|
||||
XCTAssertEqual(expectedValue2, actualValue2)
|
||||
XCTAssertEqual(actualKey2, expectedKey2)
|
||||
XCTAssertEqual(actualValue2, expectedValue2)
|
||||
|
||||
let nonExistentElement = orderedDictionary.removeAtIndex(42)
|
||||
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]
|
||||
|
||||
XCTAssertTrue(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)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Sorting
|
||||
// MARK: - Moving Elements
|
||||
// ======================================================= //
|
||||
|
||||
func testSortingInPlace() {
|
||||
let actual: OrderedDictionary<String, Int> = {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["E": 4, "G": 3, "A": 3, "D": 1, "B": 4]
|
||||
|
||||
orderedDictionary.sortInPlace { (element1: (key: String, value: Int), element2: (key: String, value: Int)) in
|
||||
if element1.value == element2.value {
|
||||
return element1.key < element2.key
|
||||
} else {
|
||||
return element1.value < element2.value
|
||||
}
|
||||
}
|
||||
|
||||
return orderedDictionary
|
||||
}()
|
||||
func testMovingElements() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
|
||||
XCTAssertEqual(orderedDictionary.moveElement(forKey: "A", to: 2), 0) // B, C, A, D
|
||||
XCTAssertEqual(orderedDictionary.moveElement(forKey: "D", to: 3), 3) // B, C, A, D
|
||||
XCTAssertEqual(orderedDictionary.moveElement(forKey: "C", to: 0), 1) // C, B, A, D
|
||||
XCTAssertEqual(orderedDictionary.moveElement(forKey: "B", to: 3), 1) // C, A, D, B
|
||||
XCTAssertEqual(orderedDictionary.moveElement(forKey: "E", to: 0), nil)
|
||||
|
||||
let actual = orderedDictionary
|
||||
let expected: OrderedDictionary<String, Int> = ["C": 3, "A": 1, "D": 4, "B": 2]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Sorting Elements
|
||||
// ======================================================= //
|
||||
|
||||
func testSortingWithMutation() {
|
||||
var orderedDictionary: OrderedDictionary<String, Int> = ["E": 4, "G": 3, "A": 3, "D": 1, "B": 4]
|
||||
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 { 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]
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Slices
|
||||
// ======================================================= //
|
||||
|
||||
func testSliceAccess() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
|
||||
let slice = orderedDictionary[2..<4]
|
||||
|
||||
XCTAssertEqual(slice.count, 2)
|
||||
XCTAssertEqual(slice.startIndex, 2)
|
||||
XCTAssertEqual(slice.endIndex, 4)
|
||||
XCTAssertEqual(Array(slice.indices), [2, 3])
|
||||
XCTAssert(slice[2] == (key: "C", value: 3))
|
||||
XCTAssert(slice[3] == (key: "D", value: 4))
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Codable
|
||||
// ======================================================= //
|
||||
|
||||
func testEncodingAndDecodingViaJSON() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = [
|
||||
"A": 42,
|
||||
"B": 100,
|
||||
"C": 11
|
||||
]
|
||||
|
||||
let jsonEncoder = JSONEncoder()
|
||||
let data = try! jsonEncoder.encode(orderedDictionary)
|
||||
let actualString = String(data: data, encoding: .utf8)
|
||||
|
||||
let expectedString = "[\"A\",42,\"B\",100,\"C\",11]"
|
||||
|
||||
XCTAssertEqual(actualString, expectedString)
|
||||
|
||||
let jsonDecoder = JSONDecoder()
|
||||
let actual = try! jsonDecoder.decode(OrderedDictionary<String, Int>.self, from: data)
|
||||
|
||||
let expected = orderedDictionary
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testEncodingAndDecodingViaPropertyList() {
|
||||
let orderedDictionary: OrderedDictionary<String, Int> = [
|
||||
"A": 42,
|
||||
"B": 100,
|
||||
"C": 11
|
||||
]
|
||||
|
||||
let plistEncoder = PropertyListEncoder()
|
||||
let data = try! plistEncoder.encode(orderedDictionary)
|
||||
|
||||
let plistDecoder = PropertyListDecoder()
|
||||
let actual = try! plistDecoder.decode(OrderedDictionary<String, Int>.self, from: data)
|
||||
|
||||
let expected = orderedDictionary
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
// ======================================================= //
|
||||
// MARK: - Description
|
||||
// ======================================================= //
|
||||
|
||||
struct DescribedValue: CustomStringConvertible, CustomDebugStringConvertible {
|
||||
init(_ value: Int) { self.value = value }
|
||||
let value: Int
|
||||
var description: String { return "\(value)" }
|
||||
var debugDescription: String { return "debug(\(value))" }
|
||||
}
|
||||
|
||||
func testEmptyDescription() {
|
||||
let orderedDictionary = OrderedDictionary<String, DescribedValue>()
|
||||
let actual = orderedDictionary.description
|
||||
|
||||
let expected = "[:]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testDescription() {
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = [
|
||||
"A": DescribedValue(1),
|
||||
"B": DescribedValue(2),
|
||||
"C": DescribedValue(3)
|
||||
]
|
||||
let actual = orderedDictionary.description
|
||||
|
||||
let expected = "[A: 1, B: 2, C: 3]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testEmptyDebugDescription() {
|
||||
let orderedDictionary = OrderedDictionary<String, DescribedValue>()
|
||||
let actual = orderedDictionary.debugDescription
|
||||
|
||||
let expected = "[:]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
func testDebugDescription() {
|
||||
let orderedDictionary: OrderedDictionary<String, DescribedValue> = [
|
||||
"A": DescribedValue(1),
|
||||
"B": DescribedValue(2),
|
||||
"C": DescribedValue(3)
|
||||
]
|
||||
let actual = orderedDictionary.debugDescription
|
||||
|
||||
let expected = "[\"A\": debug(1), \"B\": debug(2), \"C\": debug(3)]"
|
||||
|
||||
XCTAssertEqual(actual, expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user