Compare commits

...

30 Commits

Author SHA1 Message Date
Lukas Kubanek acb62df760 Bumped version to 2.4.0
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2020-03-02 10:58:22 +00:00
Lukas Kubanek f303e02f63 Merge branch 'pr-capacity'
Closes #54

Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2020-03-02 10:38:54 +00:00
Lukas Kubanek 244d0128c9 Added basic tests for capacity reservation
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2020-03-02 10:32:41 +00:00
Lukas Kubanek 0d5e16fc4f Expose min reserved capacity of underlying types
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2020-03-02 10:32:24 +00:00
Lukas Kubanek ecd3f176e5 Introduced init(minimumCapacity:)
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2020-03-02 10:26:27 +00:00
Lukas Kubanek ac3f8fa5eb Tweaked documentation comments
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2020-03-02 10:26:26 +00:00
Gal Cohen 19046fb4a8 adds capacity getter and reserveCapacity method 2020-01-31 21:30:29 -05:00
Lukas Kubanek 005ef5c3ee 2019 → 2020
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2020-01-12 10:08:56 +01:00
Lukas Kubanek 68f2557694 Updated to Xcode 11.2
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-11-04 16:53:55 +01:00
Lukas Kubanek 72d4779e9b Concretized Swift version in the recent tweak
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-09-26 16:14:02 +02:00
Lukas Kubanek 8547583792 Another try to satisfy Swift 4.0
It turns out Swift <4.1 does not understand the rethrows keyword and thus sees the newly annotated initializer as failing. Resorted to a force unwrap in the deprecated initializer as its parameter is non-throwing.

Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-09-26 16:04:40 +02:00
Lukas Kubanek 3688348461 Another attempt on fixing the bug with missing try keyword
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-09-26 15:40:41 +02:00
Lukas Kubanek f875439709 Fixed a bug introduced in the last commit
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-09-26 15:32:43 +02:00
Lukas Kubanek 1920f07525 init(values:uniquelyKeyedBy:) now takes throwing closure
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-09-26 15:03:57 +02:00
Lukas Kubanek 69ed90dcfc Bumped version to 2.3.0
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-30 15:41:05 +02:00
Lukas Kubanek 33fa9622ce Removed irrelevant part of a playground
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-30 15:40:31 +02:00
Lukas Kubanek 468ad1c83a Attempted to fix type inference issue in Swift 4
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 13:00:43 +02:00
Lukas Kubanek 174c21d58f Fixed a warning for Swift 5.0
Fixes #52

Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 12:44:37 +02:00
Lukas Kubanek 5f076fccbb init(_:) → init(uniqueKeysWithValues:)
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 12:38:22 +02:00
Lukas Kubanek 642b5623b7 init(values:keyedBy:) → init(values:uniquelyKeyedBy:)
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 12:22:32 +02:00
Lukas Kubanek 03b5817530 Annotated Travis configuration with exact 4.1.X version
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 09:42:34 +02:00
Lukas Kubanek 7ba07fcef1 Re-added Travis configurations for different Swift versions
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 09:35:49 +02:00
Lukas Kubanek 0e1273e2ab Attempt to use specified Swift versions by Travis
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 09:25:32 +02:00
Lukas Kubanek 7b8b3c39a3 Simplified Travis setup
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 09:11:26 +02:00
Lukas Kubanek 1e5c2926a7 Made tests compatible with Swift 4
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 08:56:24 +02:00
Lukas Kubanek b678702e3d Introduced mapValues(_:) & compactMapValues(_:)
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-07-12 08:38:59 +02:00
Lukas Kubanek 4e4b205dcb Revert "Disabled automatic linking"
This reverts commit b345a3e8df.
2019-07-04 14:53:30 +02:00
Lukas Kubanek b345a3e8df Disabled automatic linking
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-06-05 16:56:17 +02:00
Lukas Kubanek 2cf9220874 Updated project file to Xcode 11
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-06-04 10:13:56 +02:00
Lukas Kubanek 08e9ff5371 Minor adjustment in README
Signed-off-by: Lukas Kubanek <lukas.kubanek@me.com>
2019-04-29 14:01:50 +02:00
12 changed files with 293 additions and 107 deletions
+24 -9
View File
@@ -5,7 +5,7 @@ branches:
# OS
os: osx
language: objective-c
language: swift
# Xcode Project
xcode_project: OrderedDictionary.xcodeproj
@@ -13,31 +13,46 @@ xcode_project: OrderedDictionary.xcodeproj
# Build Matrix
matrix:
include:
# Swift 4.0 / macOS
- osx_image: xcode9.2
# Swift 5.0.1 / macOS
- osx_image: xcode10.2
xcode_scheme: OrderedDictionary-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build test"
- XCODE_DESTINATION="arch=x86_64"
- XCODE_PLAYGROUND_TARGET="x86_64-apple-macosx10.10"
# Swift 4.0 / iOS
- osx_image: xcode9.2
# Swift 5.0.1 / iOS
- osx_image: xcode10.2
xcode_scheme: OrderedDictionary-iOS
env:
- XCODE_SDK=iphonesimulator
- XCODE_ACTION="build-for-testing test-without-building"
- XCODE_DESTINATION="platform=iOS Simulator,name=iPhone 6s,OS=10.1"
# Swift 4.1 / macOS
- osx_image: xcode9.3beta
# Swift 4.1.2 / macOS
- osx_image: xcode9.4
xcode_scheme: OrderedDictionary-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build test"
- XCODE_DESTINATION="arch=x86_64"
- XCODE_PLAYGROUND_TARGET="x86_64-apple-macosx10.10"
# Swift 4.1 / iOS
- osx_image: xcode9.3beta
# Swift 4.1.2 / iOS
- osx_image: xcode9.4
xcode_scheme: OrderedDictionary-iOS
env:
- XCODE_SDK=iphonesimulator
- XCODE_ACTION="build-for-testing test-without-building"
- XCODE_DESTINATION="platform=iOS Simulator,name=iPhone 6s,OS=10.1"
# Swift 4.0.3 / macOS
- osx_image: xcode9.2
xcode_scheme: OrderedDictionary-Mac
env:
- XCODE_SDK=macosx
- XCODE_ACTION="build test"
- XCODE_DESTINATION="arch=x86_64"
- XCODE_PLAYGROUND_TARGET="x86_64-apple-macosx10.10"
# Swift 4.0.3 / iOS
- osx_image: xcode9.2
xcode_scheme: OrderedDictionary-iOS
env:
- XCODE_SDK=iphonesimulator
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015-2019 Lukas Kubanek
Copyright © 2015-2020 Lukas Kubanek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
8048C8AB22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */; };
8048C8AC22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */; };
8055B0421E201C5D009DC3EE /* OrderedDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8055B0381E201C5D009DC3EE /* OrderedDictionary.framework */; };
8055B0591E201DF3009DC3EE /* OrderedDictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8055B0581E201DF3009DC3EE /* OrderedDictionaryTests.swift */; };
80A203A11F3F483700622481 /* OrderedDictionary+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80A203A01F3F483700622481 /* OrderedDictionary+Codable.swift */; };
@@ -41,6 +43,7 @@
8024947F2277136D00AB44C7 /* Package@swift-5.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Package@swift-5.swift"; sourceTree = "<group>"; };
804879371E217C7700AD31A3 /* build.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build.sh; sourceTree = "<group>"; };
804879381E217CA100AD31A3 /* validate-playgrounds.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "validate-playgrounds.sh"; sourceTree = "<group>"; };
8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrderedDictionary+Deprecated.swift"; sourceTree = "<group>"; };
8055B0381E201C5D009DC3EE /* OrderedDictionary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OrderedDictionary.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8055B0411E201C5D009DC3EE /* OrderedDictionary_Mac_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OrderedDictionary_Mac_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8055B0581E201DF3009DC3EE /* OrderedDictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderedDictionaryTests.swift; sourceTree = "<group>"; };
@@ -135,6 +138,7 @@
80E8E21C1E20301E00395E49 /* OrderedDictionary.swift */,
80A203A01F3F483700622481 /* OrderedDictionary+Codable.swift */,
80E8E22F1E2133D100395E49 /* OrderedDictionary+Description.swift */,
8048C8AA22D8911B0086B88B /* OrderedDictionary+Deprecated.swift */,
);
path = Sources;
sourceTree = "<group>";
@@ -346,6 +350,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8048C8AB22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */,
80E8E2301E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */,
80E8E21D1E20301E00395E49 /* OrderedDictionary.swift in Sources */,
80A203A11F3F483700622481 /* OrderedDictionary+Codable.swift in Sources */,
@@ -364,6 +369,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8048C8AC22D8911B0086B88B /* OrderedDictionary+Deprecated.swift in Sources */,
80E8E2311E2133D100395E49 /* OrderedDictionary+Description.swift in Sources */,
80E8E21F1E20425B00395E49 /* OrderedDictionary.swift in Sources */,
80A203A21F3F4C1F00622481 /* OrderedDictionary+Codable.swift in Sources */,
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1120"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -27,6 +27,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
BuildableName = "OrderedDictionary.framework"
BlueprintName = "OrderedDictionary-Mac"
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@@ -39,17 +48,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8055B0371E201C5D009DC3EE"
BuildableName = "OrderedDictionary.framework"
BlueprintName = "OrderedDictionary-Mac"
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -70,8 +68,6 @@
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1120"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -27,6 +27,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
BuildableName = "OrderedDictionary.framework"
BlueprintName = "OrderedDictionary-iOS"
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@@ -39,17 +48,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "80B28E961E201EC8007E3A77"
BuildableName = "OrderedDictionary.framework"
BlueprintName = "OrderedDictionary-iOS"
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -70,8 +68,6 @@
ReferencedContainer = "container:OrderedDictionary.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -31,19 +31,3 @@ let plistDecoder = PropertyListDecoder()
let orderedDictionary3 = try! plistDecoder.decode(OrderedDictionary<String, Int>.self, from: plistData)
orderedDictionary1 == orderedDictionary3
// ======================================================= //
// MARK: - Non-codable Type
// ======================================================= //
struct NonCodableType {
var string: String
}
let orderedDictionary4: OrderedDictionary<String, NonCodableType> = [
"A" : NonCodableType(string: "Foo"),
"B" : NonCodableType(string: "Bar"),
"C" : NonCodableType(string: "Baz")
]
//try? jsonEncoder.encode(x)
+3 -3
View File
@@ -1,6 +1,6 @@
# OrderedDictionary
[![](https://img.shields.io/travis/lukaskubanek/OrderedDictionary.svg?style=flat-square "Build")](https://travis-ci.org/lukaskubanek/OrderedDictionary) [![](https://img.shields.io/badge/release-v2.2.2-blue.svg?style=flat-square)](https://github.com/lukaskubanek/OrderedDictionary/releases) [![](https://img.shields.io/badge/Swift-4.0+-orange.svg?style=flat-square)](https://developer.apple.com/swift/ "Swift 4") ![](https://img.shields.io/badge/platform-macOS/iOS-yellowgreen.svg?style=flat-square "Platform: macOS/iOS") [![](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat-square "Carthage compatible")](https://github.com/Carthage/Carthage)
[![](https://img.shields.io/travis/lukaskubanek/OrderedDictionary.svg?style=flat-square "Build")](https://travis-ci.org/lukaskubanek/OrderedDictionary) [![](https://img.shields.io/badge/release-v2.4.0-blue.svg?style=flat-square)](https://github.com/lukaskubanek/OrderedDictionary/releases) [![](https://img.shields.io/badge/Swift-4.0+-orange.svg?style=flat-square)](https://developer.apple.com/swift/ "Swift 4.0+") ![](https://img.shields.io/badge/platform-macOS/iOS-yellowgreen.svg?style=flat-square "Platform: macOS/iOS") [![](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat-square "Carthage compatible")](https://github.com/Carthage/Carthage)
[![](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat-square "SPM compatible")](https://github.com/Carthage/Carthage) [![](https://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat-square "License: MIT")](LICENSE.md)
**OrderedDictionary** is a lightweight implementation of an ordered dictionary data structure in Swift.
@@ -13,7 +13,7 @@ Internally, `OrderedDictionary` uses a backing store composed of an instance of
## Requirements
- Swift 4.0, 4.2, 5.0
- Swift 4.0+ (4.0, 4.2, 5.0, 5.1)
- Xcode 9.2+
- iOS 8.0+ / macOS 10.10+
@@ -36,7 +36,7 @@ Then, drag either the `OrderedDictionary.xcodeproj` or the `OrderedDictionary.fr
Another option is to use the [Swift Package Manager](https://swift.org/package-manager/). If you prefer this option, put OrderedDictionary as a dependency to your `Package.swift`:
```plain
.package(url: "https://github.com/lukaskubanek/OrderedDictionary.git", from: "2.2.2")
.package(url: "https://github.com/lukaskubanek/OrderedDictionary.git", from: "2.4.0")
```
#### Git Submodules
+3
View File
@@ -32,6 +32,9 @@ if [[ -z $XCODE_DESTINATION ]]; then
fi
set -o pipefail
swift --version
xcodebuild $XCODE_ACTION \
-project "$TRAVIS_XCODE_PROJECT" \
-scheme "$TRAVIS_XCODE_SCHEME" \
@@ -0,0 +1,28 @@
extension OrderedDictionary {
@available(*, deprecated, message: "Please use init(values:uniquelyKeyedBy:).", renamed: "init(values:uniquelyKeyedBy:)")
public init<S: Sequence>(
values: S,
keyedBy extractKey: (Value) -> Key
) where S.Element == Value {
#if swift(>=4.1.3)
self.init(values: values, uniquelyKeyedBy: extractKey)
#else
try! self.init(values: values, uniquelyKeyedBy: extractKey)
#endif
}
@available(*, deprecated, message: "Please use init(values:uniquelyKeyedBy:).", renamed: "init(values:uniquelyKeyedBy:)")
public init(
values: [Value],
keyedBy keyPath: KeyPath<Value, Key>
) {
self.init(values: values, uniquelyKeyedBy: keyPath)
}
@available(*, deprecated, message: "Please use init(uniqueKeysWithValues:).", renamed: "init(uniqueKeysWithValues:)")
public init<S: Sequence>(_ elements: S) where S.Element == Element {
self.init(uniqueKeysWithValues: elements)
}
}
+136 -40
View File
@@ -27,32 +27,20 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
// MARK: - Initialization
// ======================================================= //
/// Creates an empty ordered dictionary.
public init() {}
/// Creates an ordered dictionary from a sequence of values keyed by a key which gets extracted
/// from the value in the provided closure.
///
/// - Parameter values: The sequence of values.
/// - Parameter getKey: The closure which provides a key for the given value from the values
/// sequence.
public init<Values: Sequence>(
values: Values,
keyedBy getKey: (Value) -> Key
) where Values.Element == Value {
self.init(values.map { (getKey($0), $0) })
/// Initializes an empty ordered dictionary.
public init() {
self._orderedKeys = [Key]()
self._keysToValues = [Key: Value]()
}
/// Creates an ordered dictionary from a sequence of values keyed by a key loaded from the value
/// at the given key path.
///
/// - Parameter values: The sequence of values.
/// - Parameter keyPath: The key path for the value to locate its key at.
public init(values: [Value], keyedBy keyPath: KeyPath<Value, Key>) {
self.init(values.map { ($0[keyPath: keyPath], $0) })
/// Initializes an empty ordered dictionary with preallocated space for at least the specified
/// number of elements.
public init(minimumCapacity: Int) {
self.init()
self.reserveCapacity(minimumCapacity)
}
/// Creates an ordered dictionary from a regular unsorted dictionary by sorting it using the
/// Initializes an ordered dictionary from a regular unsorted dictionary by sorting it using
/// the given sort function.
///
/// - Parameter unsorted: The unsorted dictionary.
@@ -61,20 +49,65 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
unsorted: Dictionary<Key, Value>,
areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows {
let elements = try unsorted
.map { (key: $0.key, value: $0.value) }
.sorted(by: areInIncreasingOrder)
let keysAndValues = try Array(unsorted).sorted(by: areInIncreasingOrder)
self.init(elements)
self.init(
uniqueKeysWithValues: keysAndValues,
minimumCapacity: unsorted.count
)
}
/// Creates an ordered dictionary from a sequence of key-value pairs.
/// Initializes an ordered dictionary from a sequence of values keyed by a unique key extracted
/// from the value using the given closure.
///
/// - Parameter elements: The key-value pairs that will make up the new ordered dictionary.
/// Each key in `elements` must be unique.
public init<S: Sequence>(_ elements: S) where S.Element == Element {
for (key, value) in elements {
precondition(!containsKey(key), "Elements sequence contains duplicate keys")
/// - Parameter values: The sequence of values.
/// - Parameter extractKey: The closure which extracts a key from the value. The returned keys
/// must be unique for all values from the sequence.
public init<S: Sequence>(
values: S,
uniquelyKeyedBy extractKey: (Value) throws -> Key
) rethrows where S.Element == Value {
self.init(uniqueKeysWithValues: try values.map { value in
return (try extractKey(value), value)
})
}
/// Initializes an ordered dictionary from a sequence of values keyed by a unique key extracted
/// from the value using the given key path.
///
/// - Parameter values: The sequence of values.
/// - Parameter keyPath: The key path to use for extracting a key from the value. The extracted
/// keys must be unique for all values from the sequence.
public init<S: Sequence>(
values: S,
uniquelyKeyedBy keyPath: KeyPath<Value, Key>
) where S.Element == Value {
self.init(uniqueKeysWithValues: values.map { value in
return (value[keyPath: keyPath], value)
})
}
/// Initializes an ordered dictionary from a sequence of key-value pairs.
///
/// - Parameter keysAndValues: A sequence of key-value pairs to use for the new ordered
/// dictionary. Every key in `keysAndValues` must be unique.
public init<S: Sequence>(
uniqueKeysWithValues keysAndValues: S
) where S.Element == Element {
self.init(
uniqueKeysWithValues: keysAndValues,
minimumCapacity: keysAndValues.underestimatedCount
)
}
private init<S: Sequence>(
uniqueKeysWithValues keysAndValues: S,
minimumCapacity: Int
) where S.Element == Element {
self.init(minimumCapacity: minimumCapacity)
for (key, value) in keysAndValues {
precondition(!containsKey(key), "Sequence of key-value pairs contains duplicate keys")
self[key] = value
}
}
@@ -288,7 +321,11 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
/// - Returns: The index for `key` and its associated value if `key` is in the ordered
/// dictionary; otherwise, `nil`.
public func index(forKey key: Key) -> Index? {
#if swift(>=5.0)
return _orderedKeys.firstIndex(of: key)
#else
return _orderedKeys.index(of: key)
#endif
}
/// Returns the key-value pair at the specified index, or `nil` if there is no key-value pair
@@ -543,7 +580,7 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
public func sorted(
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows -> OrderedDictionary<Key, Value> {
return OrderedDictionary(try _sortedElements(by: areInIncreasingOrder))
return OrderedDictionary(uniqueKeysWithValues: try _sortedElements(by: areInIncreasingOrder))
}
private func _sortedElements(
@@ -552,15 +589,73 @@ public struct OrderedDictionary<Key: Hashable, Value>: BidirectionalCollection {
return try sorted(by: areInIncreasingOrder)
}
// ======================================================= //
// MARK: - Mapping Values
// ======================================================= //
/// Returns a new ordered dictionary containing the keys of this ordered dictionary with the
/// values transformed by the given closure by preserving the original order.
public func mapValues<T>(
_ transform: (Value) throws -> T
) rethrows -> OrderedDictionary<Key, T> {
var result = OrderedDictionary<Key, T>()
for (key, value) in self {
result[key] = try transform(value)
}
return result
}
/// Returns a new ordered dictionary containing only the key-value pairs that have non-nil
/// values as the result of transformation by the given closure by preserving the original
/// order.
public func compactMapValues<T>(
_ transform: (Value) throws -> T?
) rethrows -> OrderedDictionary<Key, T> {
var result = OrderedDictionary<Key, T>()
for (key, value) in self {
if let transformedValue = try transform(value) {
result[key] = transformedValue
}
}
return result
}
// ======================================================= //
// MARK: - Capacity
// ======================================================= //
/// The total number of elements that the ordered dictionary can contain without allocating
/// new storage.
public var capacity: Int {
return Swift.min(_orderedKeys.capacity, _keysToValues.capacity)
}
/// Reserves enough space to store the specified number of elements, when appropriate
/// for the underlying types.
///
/// If you are adding a known number of elements to an ordered dictionary, use this method
/// to avoid multiple reallocations. This method ensures that the underlying types of the
/// ordered dictionary have space allocated for at least the requested number of elements.
///
/// - Parameter minimumCapacity: The requested number of elements to store.
public mutating func reserveCapacity(_ minimumCapacity: Int) {
_orderedKeys.reserveCapacity(minimumCapacity)
_keysToValues.reserveCapacity(minimumCapacity)
}
// ======================================================= //
// MARK: - Internal Storage
// ======================================================= //
/// The backing storage for the ordered keys.
fileprivate var _orderedKeys = [Key]()
fileprivate var _orderedKeys: [Key]
/// The backing storage for the mapping of keys to values.
fileprivate var _keysToValues = [Key: Value]()
fileprivate var _keysToValues: [Key: Value]
}
@@ -612,19 +707,20 @@ public typealias OrderedDictionaryValues<Key: Hashable, Value> = LazyMapBidirect
extension OrderedDictionary: ExpressibleByArrayLiteral {
/// Creates an ordered dictionary initialized from an array literal containing a list of
/// key-value pairs.
/// Initializes an ordered dictionary initialized from an array literal containing a list of
/// key-value pairs. Every key in `elements` must be unique.
public init(arrayLiteral elements: Element...) {
self.init(elements)
self.init(uniqueKeysWithValues: elements)
}
}
extension OrderedDictionary: ExpressibleByDictionaryLiteral {
/// Creates an ordered dictionary initialized from a dictionary literal.
/// Initializes an ordered dictionary initialized from a dictionary literal. Every key in
/// `elements` must be unique.
public init(dictionaryLiteral elements: (Key, Value)...) {
self.init(elements.map { element in
self.init(uniqueKeysWithValues: elements.map { element in
let (key, value) = element
return (key: key, value: value)
})
+2 -2
View File
@@ -15,13 +15,13 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.2</string>
<string>2.4.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015-2019 Lukas Kubanek. All rights reserved.</string>
<string>Copyright © 2015-2020 Lukas Kubanek. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
+70 -8
View File
@@ -42,7 +42,7 @@ class OrderedDictionaryTests: XCTestCase {
("C", 3)
]
let expected = OrderedDictionary<String, Int>([
let expected = OrderedDictionary<String, Int>(uniqueKeysWithValues: [
(key: "A", value: 1),
(key: "B", value: 2),
(key: "C", value: 3)
@@ -58,7 +58,7 @@ class OrderedDictionaryTests: XCTestCase {
"C": 3
]
let expected = OrderedDictionary<String, Int>([
let expected = OrderedDictionary<String, Int>(uniqueKeysWithValues: [
(key: "A", value: 1),
(key: "B", value: 2),
(key: "C", value: 3)
@@ -70,10 +70,10 @@ class OrderedDictionaryTests: XCTestCase {
func testInitializationUsingValuesAndKeyProviderClosure() {
let actual = OrderedDictionary(
values: [1, 2, 3],
keyedBy: { "\($0)" }
uniquelyKeyedBy: { "\($0)" }
)
let expected = OrderedDictionary<String, Int>([
let expected = OrderedDictionary<String, Int>(uniqueKeysWithValues: [
(key: "1", value: 1),
(key: "2", value: 2),
(key: "3", value: 3)
@@ -89,10 +89,10 @@ class OrderedDictionaryTests: XCTestCase {
TestValue(string: "B"),
TestValue(string: "C")
],
keyedBy: \.string
uniquelyKeyedBy: \.string
)
let expected = OrderedDictionary<String, TestValue>([
let expected = OrderedDictionary<String, TestValue>(uniqueKeysWithValues: [
(key: "A", value: TestValue(string: "A")),
(key: "B", value: TestValue(string: "B")),
(key: "C", value: TestValue(string: "C"))
@@ -113,7 +113,7 @@ class OrderedDictionaryTests: XCTestCase {
areInIncreasingOrder: { $0.key < $1.key }
)
let expected = OrderedDictionary([
let expected = OrderedDictionary(uniqueKeysWithValues: [
(key: 1, value: "bar"),
(key: 2, value: "foo"),
(key: 3, value: "bam"),
@@ -133,7 +133,7 @@ class OrderedDictionaryTests: XCTestCase {
3: "bam"
].sorted(by: { $0.key < $1.key })
let expected = OrderedDictionary([
let expected = OrderedDictionary(uniqueKeysWithValues: [
(key: 1, value: "bar"),
(key: 2, value: "foo"),
(key: 3, value: "bam"),
@@ -511,6 +511,28 @@ class OrderedDictionaryTests: XCTestCase {
XCTAssertEqual(actual, expected)
}
// ======================================================= //
// MARK: - Mapping Values
// ======================================================= //
func testMapValues() {
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
let actual = orderedDictionary.mapValues { String($0) }
let expected: OrderedDictionary<String, String> = ["A": "1", "B": "2", "C": "3", "D": "4"]
XCTAssertEqual(actual, expected)
}
func testCompactMapValues() {
let orderedDictionary: OrderedDictionary<String, Int> = ["A": 1, "B": 2, "C": 3, "D": 4]
let actual = orderedDictionary.compactMapValues { $0 % 2 == 0 ? String($0) : nil }
let expected: OrderedDictionary<String, String> = ["B": "2", "D": "4"]
XCTAssertEqual(actual, expected)
}
// ======================================================= //
// MARK: - Slices
// ======================================================= //
@@ -527,6 +549,46 @@ class OrderedDictionaryTests: XCTestCase {
XCTAssert(slice[3] == (key: "D", value: 4))
}
// ============================================================================ //
// MARK: - Capacity
// ============================================================================ //
func testCapacityReservationViaInit() {
let orderedDictionary = OrderedDictionary<String, Int>(minimumCapacity: 10)
XCTAssertGreaterThanOrEqual(orderedDictionary.capacity, 10)
}
func testCapacityReservationViaMethod() {
var orderedDictionary = OrderedDictionary<String, Int>()
XCTAssertEqual(orderedDictionary.capacity, 0)
orderedDictionary.reserveCapacity(10)
XCTAssertGreaterThanOrEqual(orderedDictionary.capacity, 10)
XCTAssertLessThan(orderedDictionary.capacity, 20)
orderedDictionary.reserveCapacity(20)
XCTAssertGreaterThanOrEqual(orderedDictionary.capacity, 20)
}
func testCapacityGrowForElementInsertion() {
var orderedDictionary = OrderedDictionary<String, Int>()
XCTAssertEqual(orderedDictionary.capacity, 0)
orderedDictionary["A"] = 1
XCTAssertEqual(orderedDictionary.capacity, 1)
orderedDictionary["B"] = 2
orderedDictionary["A"] = 3
XCTAssertEqual(orderedDictionary.capacity, 2)
}
// ======================================================= //
// MARK: - Codable
// ======================================================= //