Skip to content

Commit fb69aac

Browse files
authored
Fix Product2's indexing logic (#26)
* Change representation of `Product2`'s `endIndex` * Fix `Product2.index(before:)` * Fix `Product2.distance(from:to:)` * Make comment more specific
1 parent 2beda36 commit fb69aac

File tree

2 files changed

+29
-19
lines changed

2 files changed

+29
-19
lines changed

Sources/Algorithms/Product.swift

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -91,27 +91,22 @@ extension Product2: Collection where Base1: Collection {
9191
}
9292

9393
public var startIndex: Index {
94-
base1.isEmpty || base2.isEmpty
95-
? endIndex
96-
: Index(i1: base1.startIndex, i2: base2.startIndex)
94+
Index(
95+
i1: base2.isEmpty ? base1.endIndex : base1.startIndex,
96+
i2: base2.startIndex)
9797
}
9898

9999
public var endIndex: Index {
100-
Index(i1: base1.endIndex, i2: base2.endIndex)
100+
// `base2.startIndex` simplifies index calculations.
101+
Index(i1: base1.endIndex, i2: base2.startIndex)
101102
}
102103

103104
public func index(after i: Index) -> Index {
104-
precondition(i.i1 != base1.endIndex && i.i2 != base2.endIndex,
105-
"Can't advance past endIndex")
105+
precondition(i.i1 != base1.endIndex, "Can't advance past endIndex")
106106
let newIndex2 = base2.index(after: i.i2)
107-
if newIndex2 < base2.endIndex {
108-
return Index(i1: i.i1, i2: newIndex2)
109-
}
110-
111-
let newIndex1 = base1.index(after: i.i1)
112-
return newIndex1 == base1.endIndex
113-
? endIndex
114-
: Index(i1: newIndex1, i2: base2.startIndex)
107+
return newIndex2 == base2.endIndex
108+
? Index(i1: base1.index(after: i.i1), i2: base2.startIndex)
109+
: Index(i1: i.i1, i2: newIndex2)
115110
}
116111

117112
// TODO: Implement index(_:offsetBy:) and index(_:offsetBy:limitedBy:)
@@ -125,7 +120,7 @@ extension Product2: Collection where Base1: Collection {
125120
}
126121

127122
return base2[start.i2...].count + base2[..<end.i2].count
128-
+ base2.count * (base1.distance(from: start.i1, to: end.i1))
123+
+ base2.count * (base1.distance(from: start.i1, to: end.i1) - 1)
129124
}
130125

131126
public subscript(position: Index) -> (Base1.Element, Base2.Element) {
@@ -140,12 +135,12 @@ extension Product2: BidirectionalCollection
140135
precondition(i != startIndex,
141136
"Can't move before startIndex")
142137
if i.i2 == base2.startIndex {
138+
return Index(
139+
i1: base1.index(before: i.i1),
140+
i2: base2.index(before: base2.endIndex))
141+
} else {
143142
return Index(i1: i.i1, i2: base2.index(before: i.i2))
144143
}
145-
146-
return Index(
147-
i1: base1.index(before: i.i1),
148-
i2: base2.index(before: base2.endIndex))
149144
}
150145
}
151146

Tests/SwiftAlgorithmsTests/ProductTests.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,19 @@ final class ProductTests: XCTestCase {
2222
XCTAssertEqualSequences(product(1...10, ""), [], by: ==)
2323
XCTAssertEqualSequences(product("", 1...10), [], by: ==)
2424
}
25+
26+
func testProductReversed() {
27+
XCTAssertEqualSequences(
28+
[(2, "B" as Character), (2, "A"), (1, "B"), (1, "A")],
29+
product(1...2, "AB").reversed(),
30+
by: ==)
31+
32+
XCTAssertEqualSequences(product(1...10, "").reversed(), [], by: ==)
33+
XCTAssertEqualSequences(product("", 1...10).reversed(), [], by: ==)
34+
}
35+
36+
func testProductDistanceFromTo() {
37+
let p = product([1, 2], "abc")
38+
XCTAssertEqual(p.distance(from: p.startIndex, to: p.endIndex), 6)
39+
}
2540
}

0 commit comments

Comments
 (0)