Skip to content

Commit 6f7148d

Browse files
committed
Implementation of feedback from @timvermeulen
1 parent dcdef50 commit 6f7148d

File tree

2 files changed

+59
-23
lines changed

2 files changed

+59
-23
lines changed

Sources/Algorithms/Stride.swift

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -86,42 +86,73 @@ extension Stride: Collection {
8686
precondition(i.base < base.endIndex, "Advancing past end index")
8787
return index(i, offsetBy: 1)
8888
}
89-
89+
9090
public func index(
9191
_ i: Index,
9292
offsetBy n: Int,
9393
limitedBy limit: Index
9494
) -> Index? {
9595
guard n != 0 else { return i }
9696
guard limit != i else { return nil }
97-
switch (i, n) {
98-
case (endIndex, ..<0):
99-
let baseEnd = base.index(base.endIndex, offsetBy: -((base.count - 1) % stride + 1))
100-
return Index(base.index(baseEnd, offsetBy: (n - n.signum()) * stride, limitedBy: limit.base))
101-
case (_, 1...):
102-
let max = limit < i ? endIndex.base : limit.base
103-
let idx = base.index(i.base, offsetBy: n * stride, limitedBy: max)
104-
if let idx = idx {
105-
return idx > max ? endIndex : Index(idx)
106-
}
107-
guard i >= limit || limit == endIndex else {
108-
return nil
97+
98+
return n > 0
99+
? offsetForward(i, offsetBy: n, limitedBy: limit)
100+
: offsetBackward(i, offsetBy: n, limitedBy: limit)
101+
}
102+
103+
private func offsetForward(
104+
_ i: Index,
105+
offsetBy n: Int,
106+
limitedBy limit: Index
107+
) -> Index? {
108+
if limit < i {
109+
if let idx = base.index(
110+
i.base,
111+
offsetBy: n * stride,
112+
limitedBy: base.endIndex
113+
) {
114+
return Index(idx)
115+
} else {
116+
assert(distance(from: i, to: endIndex) == n, "Advancing past end index")
117+
return endIndex
109118
}
110-
let isToEnd = distance(from: i, to: endIndex) == n
111-
return isToEnd ? endIndex : nil
112-
case _:
113-
return Index(base.index(i.base, offsetBy: n * stride, limitedBy: limit.base))
119+
} else if let idx = base.index(
120+
i.base,
121+
offsetBy: n * stride,
122+
limitedBy: limit.base
123+
) {
124+
return Index(idx)
125+
} else {
126+
return distance(from: i, to: limit) == n
127+
? endIndex
128+
: nil
114129
}
115130
}
116-
131+
132+
private func offsetBackward(
133+
_ i: Index,
134+
offsetBy n: Int,
135+
limitedBy limit: Index
136+
) -> Index? {
137+
let distance = i == endIndex
138+
? -((base.count - 1) % stride + 1) + (n + 1) * stride
139+
: n * stride
140+
return Index(
141+
base.index(
142+
i.base,
143+
offsetBy: distance,
144+
limitedBy: limit.base
145+
)
146+
)
147+
}
148+
117149
public var count: Int {
118-
let limit = base.count - 1
119-
return limit / stride + (limit < 0 ? 0 : 1)
150+
base.isEmpty ? 0 : (base.count - 1) / stride + 1
120151
}
121152

122153
public func distance(from start: Index, to end: Index) -> Int {
123154
let distance = base.distance(from: start.base, to: end.base)
124-
return distance / stride + (abs(distance % stride) > 0 ? distance.signum() : 0)
155+
return distance / stride + (distance % stride).signum()
125156
}
126157

127158
public func index(_ i: Index, offsetBy distance: Int) -> Index {

Tests/SwiftAlgorithmsTests/StrideTests.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,18 @@ final class StridingTests: XCTestCase {
8989
}
9090

9191
func testIndexTraversals() {
92+
let empty = [Int]()
93+
validateIndexTraversals(
94+
empty.striding(by: 1),
95+
empty.striding(by: 2)
96+
)
9297
let zero_to_one_hundered_range = 0...100
9398
validateIndexTraversals(
9499
zero_to_one_hundered_range.striding(by: 10),
95100
zero_to_one_hundered_range.striding(by: 11),
96101
zero_to_one_hundered_range.striding(by: 101)
97102
)
98-
let zero_to_one_hundered_array = zero_to_one_hundered_range.map{ $0 }
103+
let zero_to_one_hundered_array = Array(zero_to_one_hundered_range)
99104
validateIndexTraversals(
100105
zero_to_one_hundered_array.striding(by: 10),
101106
zero_to_one_hundered_array.striding(by: 11),
@@ -113,7 +118,7 @@ final class StridingTests: XCTestCase {
113118
func testOffsetBy() {
114119
let a = (0...100).striding(by: 22)
115120
let b = [0, 22, 44, 66, 88]
116-
for i in 0..<a.count {
121+
for i in 0..<a.count {
117122
XCTAssertEqual(a[a.index(a.startIndex, offsetBy: i)], b[i])
118123
}
119124
}

0 commit comments

Comments
 (0)