Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.1
3.1.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?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>classNames</key>
<dict>
<key>EquatableByKeyPathPerformanceTests</key>
<dict>
<key>testEqualityPerformance()</key>
<dict>
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.016547</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
</dict>
</dict>
<key>HashableByKeyPathPerformanceTests</key>
<dict>
<key>testEqualityPerformance()</key>
<dict>
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.017176</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
</dict>
<key>testHashPerformance()</key>
<dict>
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.010787</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
</dict>
</dict>
<key>HashableByKeyPathTests</key>
<dict>
<key>testEqualityPerformance()</key>
<dict>
<key>com.apple.dt.XCTMetric_Clock.time.monotonic</key>
<dict>
<key>baselineAverage</key>
<real>0.026650</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
<key>com.apple.dt.XCTMetric_Memory.physical</key>
<dict>
<key>baselineAverage</key>
<real>3.276800</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
<key>com.apple.dt.XCTMetric_Memory.physical_peak</key>
<dict>
<key>baselineAverage</key>
<real>0.000000</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
</dict>
<key>testHashPerformance()</key>
<dict>
<key>com.apple.dt.XCTMetric_Clock.time.monotonic</key>
<dict>
<key>baselineAverage</key>
<real>0.029324</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
<key>com.apple.dt.XCTMetric_Memory.physical</key>
<dict>
<key>baselineAverage</key>
<real>3.276800</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
<key>com.apple.dt.XCTMetric_Memory.physical_peak</key>
<dict>
<key>baselineAverage</key>
<real>0.000000</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
</dict>
</dict>
</dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?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>runDestinationsByUUID</key>
<dict>
<key>78031180-13A0-4520-92AA-B9A7A0AA4431</key>
<dict>
<key>localComputer</key>
<dict>
<key>busSpeedInMHz</key>
<integer>0</integer>
<key>cpuCount</key>
<integer>1</integer>
<key>cpuKind</key>
<string>Apple M1 Pro</string>
<key>cpuSpeedInMHz</key>
<integer>0</integer>
<key>logicalCPUCoresPerPackage</key>
<integer>10</integer>
<key>modelCode</key>
<string>MacBookPro18,1</string>
<key>physicalCPUCoresPerPackage</key>
<integer>10</integer>
<key>platformIdentifier</key>
<string>com.apple.platform.macosx</string>
</dict>
<key>targetArchitecture</key>
<string>arm64</string>
</dict>
</dict>
</dict>
</plist>
10 changes: 10 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/HashableByKeyPath.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "HashableByKeyPathPerformanceTests"
BuildableName = "HashableByKeyPathPerformanceTests"
BlueprintName = "HashableByKeyPathPerformanceTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1410"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "HashableByKeyPathPerformanceTests"
BuildableName = "HashableByKeyPathPerformanceTests"
BlueprintName = "HashableByKeyPathPerformanceTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ let package = Package(
targets: [
.target(name: "HashableByKeyPath"),
.testTarget(name: "HashableByKeyPathTests", dependencies: ["HashableByKeyPath"]),
.testTarget(name: "HashableByKeyPathPerformanceTests", dependencies: ["HashableByKeyPath"]),
]
)
23 changes: 0 additions & 23 deletions Sources/HashableByKeyPath/EquatabilityKeyPathAggregator.swift

This file was deleted.

9 changes: 2 additions & 7 deletions Sources/HashableByKeyPath/EquatableByKeyPath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,17 @@
A protocol that defines a single function that can be used to synthesise `Equatable` conformance.
*/
public protocol EquatableByKeyPath: Equatable {

/**
Add key paths to `consumer` that will be used for `Equatable` conformance.

- parameter consumer: The consumer to add the key paths to.
*/
static func addEquatableKeyPaths<Consumer: EquatableKeyPathConsumer>(to consumer: inout Consumer) where Consumer.Root == Self

}

extension EquatableByKeyPath {

public static func == (lhs: Self, rhs: Self) -> Bool {
var aggregator = EquatabilityKeyPathAggregator<Self>()
addEquatableKeyPaths(to: &aggregator)
return aggregator.evaluateEquality(lhs: lhs, rhs: rhs)
var evaluator = EquatableByKeyPathEvaluator(lhs: lhs, rhs: rhs)
return evaluator.checkEquality()
}

}
28 changes: 28 additions & 0 deletions Sources/HashableByKeyPath/EquatableByKeyPathEvaluator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
internal struct EquatableByKeyPathEvaluator<Root: EquatableByKeyPath>: EquatableKeyPathConsumer {
private let lhs: Root
private let rhs: Root
private var hasFoundNotEqualProperty = false

init(lhs: Root, rhs: Root) {
self.lhs = lhs
self.rhs = rhs
}

internal mutating func checkEquality() -> Bool {
hasFoundNotEqualProperty = false
Root.addEquatableKeyPaths(to: &self)
return !hasFoundNotEqualProperty
}

internal mutating func addEquatableKeyPath<KeyType>(_ keyPath: KeyPath<Root, KeyType>) where KeyType: Equatable {
guard !hasFoundNotEqualProperty else { return }

hasFoundNotEqualProperty = lhs[keyPath: keyPath] != rhs[keyPath: keyPath]
}

internal mutating func addCustomEquator<KeyType>(forKeyPath keyPath: KeyPath<Root, KeyType>, equator: @escaping (KeyType, KeyType) -> Bool) where KeyType: Equatable {
guard !hasFoundNotEqualProperty else { return }

hasFoundNotEqualProperty = !equator(lhs[keyPath: keyPath], rhs[keyPath: keyPath])
}
}
2 changes: 0 additions & 2 deletions Sources/HashableByKeyPath/EquatableKeyPathConsumer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
A protocol that defines a function that can be used to add key paths from the `Root` type to `Equatable` properties.
*/
public protocol EquatableKeyPathConsumer {

/// The root type of the object that will be equated.
associatedtype Root

Expand All @@ -19,5 +18,4 @@ public protocol EquatableKeyPathConsumer {
- parameter keyPath: The key to include when equating 2 instances of `Root`.
*/
mutating func addCustomEquator<KeyType>(forKeyPath keyPath: KeyPath<Root, KeyType>, equator: @escaping (KeyType, KeyType) -> Bool) where KeyType: Equatable

}
6 changes: 3 additions & 3 deletions Sources/HashableByKeyPath/HashableByKeyPath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ extension HashableByKeyPath {
}

public func hash(into hasher: inout Hasher) {
var hashableKeyPathAggregator = HashableKeyPathAggregator<Self>()
Self.addHashableKeyPaths(to: &hashableKeyPathAggregator)
return hashableKeyPathAggregator.hashValues(from: self, into: &hasher)
var keyPathHasher = KeyPathHasher<Self>(root: self, hasher: hasher)
Self.addHashableKeyPaths(to: &keyPathHasher)
hasher = keyPathHasher.hasher
}

}
36 changes: 0 additions & 36 deletions Sources/HashableByKeyPath/HashableKeyPathAggregator.swift

This file was deleted.

4 changes: 2 additions & 2 deletions Sources/HashableByKeyPath/HashableKeyPathForwarder.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
internal struct HashableKeyPathForwarder<Root, Consumer: EquatableKeyPathConsumer>: HashableKeyPathConsumer where Consumer.Root == Root {

internal typealias KeyPathListener<KeyType: Equatable> = (_ keyPath: KeyPath<Root, KeyType>) -> Void

internal var equatableKeyPathConsumer: Consumer
Expand All @@ -8,12 +7,13 @@ internal struct HashableKeyPathForwarder<Root, Consumer: EquatableKeyPathConsume
self.equatableKeyPathConsumer = equatableKeyPathConsumer
}

@inlinable
internal mutating func addHashableKeyPath<KeyType>(_ keyPath: KeyPath<Root, KeyType>) where KeyType: Hashable {
equatableKeyPathConsumer.addEquatableKeyPath(keyPath)
}

@inlinable
internal mutating func addCustomEquator<KeyType>(forKeyPath keyPath: KeyPath<Root, KeyType>, equator: @escaping (KeyType, KeyType) -> Bool) where KeyType: Hashable {
equatableKeyPathConsumer.addCustomEquator(forKeyPath: keyPath, equator: equator)
}

}
19 changes: 19 additions & 0 deletions Sources/HashableByKeyPath/KeyPathHasher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
internal struct KeyPathHasher<Root>: HashableKeyPathConsumer {
internal private(set) var hasher: Hasher

private let root: Root

internal init(root: Root, hasher: Hasher) {
self.root = root
self.hasher = hasher
}

@inlinable
internal mutating func addHashableKeyPath<KeyType>(_ keyPath: KeyPath<Root, KeyType>) where KeyType: Hashable {
hasher.combine(root[keyPath: keyPath])
}

internal mutating func addCustomEquator<KeyType>(forKeyPath keyPath: KeyPath<Root, KeyType>, equator: @escaping (KeyType, KeyType) -> Bool) where KeyType: Hashable {
// `KeyPathHasher` is never used for equality.
}
}
Loading