Skip to content

Commit abc5559

Browse files
author
Tim Vermeulen
authored
Remove collection conformances to Equatable and Hashable (#124)
1 parent bcdbac8 commit abc5559

14 files changed

+2
-209
lines changed

Guides/Compacted.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ extension Collection {
3131
```
3232

3333
One is a more general `CompactedSequence` for any `Sequence` base. And the other a more specialized `CompactedCollection`
34-
where base is a `Collection` and with conditional conformance to `BidirectionalCollection`, `RandomAccessCollection`,
35-
`LazyCollectionProtocol`, `Equatable` and `Hashable` when base collection conforms to them.
34+
where base is a `Collection` and with conditional conformance to `BidirectionalCollection`, `RandomAccessCollection` and
35+
`LazyCollectionProtocol` when base collection conforms to them.
3636

3737
### Naming
3838

Sources/Algorithms/Chain.swift

-3
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,6 @@ extension Chain2: BidirectionalCollection
283283
extension Chain2: RandomAccessCollection
284284
where Base1: RandomAccessCollection, Base2: RandomAccessCollection {}
285285

286-
extension Chain2: Equatable where Base1: Equatable, Base2: Equatable {}
287-
extension Chain2: Hashable where Base1: Hashable, Base2: Hashable {}
288-
289286
//===----------------------------------------------------------------------===//
290287
// chain(_:_:)
291288
//===----------------------------------------------------------------------===//

Sources/Algorithms/Chunked.swift

-15
Original file line numberDiff line numberDiff line change
@@ -512,21 +512,6 @@ extension Collection {
512512
}
513513
}
514514

515-
// Conditional conformances.
516-
extension ChunkedByCount: Equatable where Base: Equatable {}
517-
518-
// Since we have another stored property of type `Index` on the
519-
// collection, synthesis of `Hashble` conformace would require
520-
// a `Base.Index: Hashable` constraint, so we implement the hasher
521-
// only in terms of `base` and `chunkCount`. Since the computed
522-
// index is based on it, it should not make a difference here.
523-
extension ChunkedByCount: Hashable where Base: Hashable {
524-
@inlinable
525-
public func hash(into hasher: inout Hasher) {
526-
hasher.combine(base)
527-
hasher.combine(chunkCount)
528-
}
529-
}
530515
extension ChunkedByCount.Index: Hashable where Base.Index: Hashable {}
531516

532517
// Lazy conditional conformance.

Sources/Algorithms/Combinations.swift

-2
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,6 @@ extension Combinations: Sequence {
181181
}
182182

183183
extension Combinations: LazySequenceProtocol where Base: LazySequenceProtocol {}
184-
extension Combinations: Equatable where Base: Equatable {}
185-
extension Combinations: Hashable where Base: Hashable {}
186184

187185
//===----------------------------------------------------------------------===//
188186
// combinations(ofCount:)

Sources/Algorithms/Compacted.swift

-45
Original file line numberDiff line numberDiff line change
@@ -179,48 +179,3 @@ extension CompactedCollection: LazySequenceProtocol
179179
where Base: LazySequenceProtocol {}
180180
extension CompactedCollection: LazyCollectionProtocol
181181
where Base: LazyCollectionProtocol {}
182-
183-
184-
// Hashable and Equatable conformance are based on each non-nil
185-
// element on base collection.
186-
extension CompactedSequence: Equatable
187-
where Base.Element: Equatable {
188-
189-
@inlinable
190-
public static func ==(lhs: CompactedSequence,
191-
rhs: CompactedSequence) -> Bool {
192-
lhs.elementsEqual(rhs)
193-
}
194-
}
195-
196-
extension CompactedSequence: Hashable
197-
where Element: Hashable {
198-
199-
@inlinable
200-
public func hash(into hasher: inout Hasher) {
201-
for element in self {
202-
hasher.combine(element)
203-
}
204-
}
205-
}
206-
207-
extension CompactedCollection: Equatable
208-
where Base.Element: Equatable {
209-
210-
@inlinable
211-
public static func ==(lhs: CompactedCollection,
212-
rhs: CompactedCollection) -> Bool {
213-
lhs.elementsEqual(rhs)
214-
}
215-
}
216-
217-
extension CompactedCollection: Hashable
218-
where Element: Hashable {
219-
220-
@inlinable
221-
public func hash(into hasher: inout Hasher) {
222-
for element in self {
223-
hasher.combine(element)
224-
}
225-
}
226-
}

Sources/Algorithms/Cycle.swift

-3
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,6 @@ extension FiniteCycle: BidirectionalCollection
163163
extension FiniteCycle: RandomAccessCollection
164164
where Base: RandomAccessCollection {}
165165

166-
extension FiniteCycle: Equatable where Base: Equatable {}
167-
extension FiniteCycle: Hashable where Base: Hashable {}
168-
169166
//===----------------------------------------------------------------------===//
170167
// cycled()
171168
//===----------------------------------------------------------------------===//

Sources/Algorithms/Indexed.swift

-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ extension Indexed: BidirectionalCollection where Base: BidirectionalCollection {
7272
extension Indexed: RandomAccessCollection where Base: RandomAccessCollection {}
7373
extension Indexed: LazySequenceProtocol where Base: LazySequenceProtocol {}
7474
extension Indexed: LazyCollectionProtocol where Base: LazyCollectionProtocol {}
75-
extension Indexed: Equatable where Base: Equatable {}
76-
extension Indexed: Hashable where Base: Hashable {}
7775

7876
//===----------------------------------------------------------------------===//
7977
// indexed()

Sources/Algorithms/Product.swift

-2
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,6 @@ extension Product2: RandomAccessCollection
438438
where Base1: RandomAccessCollection, Base2: RandomAccessCollection {}
439439

440440
extension Product2.Index: Hashable where Base1.Index: Hashable, Base2.Index: Hashable {}
441-
extension Product2: Equatable where Base1: Equatable, Base2: Equatable {}
442-
extension Product2: Hashable where Base1: Hashable, Base2: Hashable {}
443441

444442
//===----------------------------------------------------------------------===//
445443
// product(_:_:)

Sources/Algorithms/Stride.swift

-18
Original file line numberDiff line numberDiff line change
@@ -269,22 +269,4 @@ extension StrideCollection: BidirectionalCollection
269269
}
270270

271271
extension StrideCollection: RandomAccessCollection where Base: RandomAccessCollection {}
272-
273-
extension StrideCollection: Equatable where Base.Element: Equatable {
274-
@inlinable
275-
public static func == (lhs: StrideCollection, rhs: StrideCollection) -> Bool {
276-
lhs.elementsEqual(rhs, by: ==)
277-
}
278-
}
279-
280-
extension StrideCollection: Hashable where Base.Element: Hashable {
281-
@inlinable
282-
public func hash(into hasher: inout Hasher) {
283-
hasher.combine(stride)
284-
for element in self {
285-
hasher.combine(element)
286-
}
287-
}
288-
}
289-
290272
extension StrideCollection.Index: Hashable where Base.Index: Hashable {}

Sources/Algorithms/Windows.swift

-2
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,4 @@ extension Windows: BidirectionalCollection where Base: BidirectionalCollection {
350350
extension Windows: LazySequenceProtocol where Base: LazySequenceProtocol {}
351351
extension Windows: LazyCollectionProtocol where Base: LazyCollectionProtocol {}
352352
extension Windows: RandomAccessCollection where Base: RandomAccessCollection {}
353-
extension Windows: Equatable where Base: Equatable {}
354-
extension Windows: Hashable where Base: Hashable, Base.Index: Hashable {}
355353
extension Windows.Index: Hashable where Base.Index: Hashable {}

Tests/SwiftAlgorithmsTests/ChunkedTests.swift

-12
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,4 @@ final class ChunkedTests: XCTestCase {
145145
validateIndexTraversals(chunks)
146146
}
147147
}
148-
149-
func testChunksOfCountHash() {
150-
let collection1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
151-
let collection2 = [1, 2, 3, 4, 5]
152-
153-
XCTAssertEqualHashValue(
154-
collection1.chunks(ofCount: 1), collection1.chunks(ofCount: 1))
155-
XCTAssertNotEqualHashValue(
156-
collection1.chunks(ofCount: 1), collection2.chunks(ofCount: 1))
157-
XCTAssertNotEqualHashValue(
158-
collection1.chunks(ofCount: 2), collection2.chunks(ofCount: 4))
159-
}
160148
}

Tests/SwiftAlgorithmsTests/CompactedTests.swift

-37
Original file line numberDiff line numberDiff line change
@@ -41,41 +41,4 @@ final class CompactedTests: XCTestCase {
4141
validateIndexTraversals(array.compacted())
4242
}
4343
}
44-
45-
func testCollectionEquatableConformances() {
46-
for array in self.tests {
47-
XCTAssertEqual(
48-
array.eraseToAnyHashableSequence().compacted(),
49-
array.compactMap({ $0 }).eraseToAnyHashableSequence().compacted()
50-
)
51-
XCTAssertEqual(
52-
array.compacted(), array.compactMap({ $0 }).compacted()
53-
)
54-
}
55-
}
56-
57-
func testCollectionHashableConformances() {
58-
for array1 in self.tests {
59-
for array2 in self.tests {
60-
// For non-equal Collections and Sequences that produce the same
61-
// compacted, the compacted wrapper should produce the same hash.
62-
// e.g. [1, 2, 3, nil, nil, 4].compacted() should produce the
63-
// same hash as [1, nil, 2, nil, 3, 4].compacted()
64-
guard !array1.elementsEqual(array2) &&
65-
array1.compacted() == array2.compacted() else {
66-
continue
67-
}
68-
69-
let seq = array1.eraseToAnyHashableSequence()
70-
let seq2 = array2.eraseToAnyHashableSequence()
71-
72-
XCTAssertEqualHashValue(
73-
seq.compacted(), seq2.compacted()
74-
)
75-
XCTAssertEqualHashValue(
76-
array1.compacted(), array2.compacted()
77-
)
78-
}
79-
}
80-
}
8144
}

Tests/SwiftAlgorithmsTests/StrideTests.swift

-13
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,6 @@ final class StridingTests: XCTestCase {
6464
// a.index(after: a.endIndex) // Precondition failed: Advancing past end index
6565
}
6666

67-
func testStrideCompositionEquivalence() {
68-
let a = (0...10)
69-
XCTAssertEqualSequences(a.striding(by: 6), a.striding(by: 2).striding(by: 3))
70-
XCTAssertTrue(a.striding(by: 6) == a.striding(by: 2).striding(by: 3))
71-
XCTAssert(type(of: a.striding(by: 2).striding(by: 3)) == StrideCollection<ClosedRange<Int>>.self)
72-
}
73-
74-
func testEquality() {
75-
let a = [1, 2, 3, 4, 5].striding(by: 2)
76-
let b = [1, 0, 3, 0, 5].striding(by: 2)
77-
XCTAssertEqual(a, b)
78-
}
79-
8067
func testStrideLast() {
8168
XCTAssertEqual((1...10).striding(by: 2).last, 9) // 1, 3, 5, 7, 9
8269
XCTAssertEqual((1...10).striding(by: 3).last, 10) // 1, 4, 7, 10

Tests/SwiftAlgorithmsTests/TestUtilities.swift

-53
Original file line numberDiff line numberDiff line change
@@ -46,27 +46,6 @@ struct SplitMix64: RandomNumberGenerator {
4646
}
4747
}
4848

49-
// An eraser helper to any hashable sequence.
50-
struct AnyHashableSequence<Base>
51-
where Base: Sequence, Base: Hashable {
52-
var base: Base
53-
}
54-
55-
extension AnyHashableSequence: Hashable {}
56-
extension AnyHashableSequence: Sequence {
57-
typealias Iterator = Base.Iterator
58-
59-
func makeIterator() -> Iterator {
60-
base.makeIterator()
61-
}
62-
}
63-
64-
extension Sequence where Self: Hashable {
65-
func eraseToAnyHashableSequence() -> AnyHashableSequence<Self> {
66-
AnyHashableSequence(base: self)
67-
}
68-
}
69-
7049
// An eraser helper to any mutable collection
7150
struct AnyMutableCollection<Base> where Base: MutableCollection {
7251
var base: Base
@@ -184,38 +163,6 @@ func XCTAssertEqualCollections<C1: Collection, C2: Collection>(
184163
}
185164
}
186165

187-
func hash<T: Hashable>(_ value: T) -> Int {
188-
var hasher = Hasher()
189-
value.hash(into: &hasher)
190-
return hasher.finalize()
191-
}
192-
193-
/// Asserts that two hashable instances produce the same hash value.
194-
func XCTAssertEqualHashValue<T: Hashable, U: Hashable>(
195-
_ expression1: @autoclosure () throws -> T,
196-
_ expression2: @autoclosure () throws -> U,
197-
_ message: @autoclosure () -> String = "",
198-
file: StaticString = #file, line: UInt = #line
199-
) {
200-
XCTAssertEqual(
201-
hash(try expression1()), hash(try expression2()),
202-
message(), file: file, line: line
203-
)
204-
}
205-
206-
/// Asserts that two hashable instances don't produce the same hash value.
207-
func XCTAssertNotEqualHashValue<T: Hashable, U: Hashable>(
208-
_ expression1: @autoclosure () throws -> T,
209-
_ expression2: @autoclosure () throws -> U,
210-
_ message: @autoclosure () -> String = "",
211-
file: StaticString = #file, line: UInt = #line
212-
) {
213-
XCTAssertNotEqual(
214-
hash(try expression1()), hash(try expression2()),
215-
message(), file: file, line: line
216-
)
217-
}
218-
219166
/// Tests that all index traversal methods behave as expected.
220167
///
221168
/// Verifies the correctness of the implementations of `startIndex`, `endIndex`,

0 commit comments

Comments
 (0)