Skip to content

Commit 18ec850

Browse files
ollieatkinsonTim Vermeulen
andauthored
Improve the performance of Stride when Base isa Collection (#88)
* Implement StrideSequence so that the default implementation for collection uses IndexingIterator * Update Sources/Algorithms/Stride.swift Co-authored-by: Tim Vermeulen <[email protected]> * reinstate documentation for Sequence and remove explicit Sequence conformance on Stride * documentation * rename Stride to StrideCollection Co-authored-by: Tim Vermeulen <[email protected]>
1 parent ab0ec2a commit 18ec850

File tree

2 files changed

+67
-22
lines changed

2 files changed

+67
-22
lines changed

Sources/Algorithms/Stride.swift

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,25 @@
1414
//===----------------------------------------------------------------------===//
1515

1616
extension Sequence {
17+
/// Returns a sequence stepping through the elements every `step` starting
18+
/// at the first value. Any remainders of the stride will be trimmed.
19+
///
20+
/// (0...10).striding(by: 2) // == [0, 2, 4, 6, 8, 10]
21+
/// (0...10).striding(by: 3) // == [0, 3, 6, 9]
22+
///
23+
/// - Complexity: O(1). Access to successive values is O(k) where
24+
/// _k_ is the striding `step`.
25+
///
26+
/// - Parameter step: The amount to step with each iteration.
27+
/// - Returns: Returns a sequence for stepping through the
28+
/// elements by the specified amount.
29+
@inlinable
30+
public func striding(by step: Int) -> StrideSequence<Self> {
31+
StrideSequence(base: self, stride: step)
32+
}
33+
}
34+
35+
extension Collection {
1736
/// Returns a sequence stepping through the elements every `step` starting
1837
/// at the first value. Any remainders of the stride will be trimmed.
1938
///
@@ -25,16 +44,17 @@ extension Sequence {
2544
/// O(_k_), where _k_ is the striding `step`.
2645
///
2746
/// - Parameter step: The amount to step with each iteration.
28-
/// - Returns: Returns a sequence or collection for stepping through the
47+
/// - Returns: Returns a collection for stepping through the
2948
/// elements by the specified amount.
3049
@inlinable
31-
public func striding(by step: Int) -> Stride<Self> {
32-
Stride(base: self, stride: step)
50+
public func striding(by step: Int) -> StrideCollection<Self> {
51+
StrideCollection(base: self, stride: step)
3352
}
3453
}
3554

36-
/// A wrapper that strides over a base sequence or collection.
37-
public struct Stride<Base: Sequence> {
55+
/// A wrapper that strides over a base sequence.
56+
public struct StrideSequence<Base: Sequence>: Sequence {
57+
3858
@usableFromInline
3959
internal let base: Base
4060

@@ -49,14 +69,8 @@ public struct Stride<Base: Sequence> {
4969
}
5070
}
5171

52-
extension Stride {
53-
@inlinable
54-
public func striding(by step: Int) -> Self {
55-
Stride(base: base, stride: stride * step)
56-
}
57-
}
58-
59-
extension Stride: Sequence {
72+
extension StrideSequence {
73+
6074
/// An iterator over a `Stride` sequence.
6175
public struct Iterator: IteratorProtocol {
6276
@usableFromInline
@@ -88,12 +102,43 @@ extension Stride: Sequence {
88102
}
89103

90104
@inlinable
91-
public func makeIterator() -> Stride<Base>.Iterator {
105+
public func makeIterator() -> Iterator {
92106
Iterator(iterator: base.makeIterator(), stride: stride)
93107
}
94108
}
95109

96-
extension Stride: Collection where Base: Collection {
110+
extension StrideSequence {
111+
@inlinable
112+
public func striding(by step: Int) -> Self {
113+
Self(base: base, stride: stride * step)
114+
}
115+
}
116+
117+
/// A wrapper that strides over a base collection.
118+
public struct StrideCollection<Base: Collection> {
119+
@usableFromInline
120+
internal let base: Base
121+
122+
@usableFromInline
123+
internal let stride: Int
124+
125+
@usableFromInline
126+
internal init(base: Base, stride: Int) {
127+
precondition(stride > 0, "striding must be greater than zero")
128+
self.base = base
129+
self.stride = stride
130+
}
131+
}
132+
133+
extension StrideCollection {
134+
@inlinable
135+
public func striding(by step: Int) -> Self {
136+
Self(base: base, stride: stride * step)
137+
}
138+
}
139+
140+
extension StrideCollection: Collection {
141+
97142
/// A position in a `Stride` collection.
98143
public struct Index: Comparable {
99144
@usableFromInline
@@ -213,7 +258,7 @@ extension Stride: Collection where Base: Collection {
213258
}
214259
}
215260

216-
extension Stride: BidirectionalCollection
261+
extension StrideCollection: BidirectionalCollection
217262
where Base: RandomAccessCollection {
218263

219264
@inlinable
@@ -223,16 +268,16 @@ extension Stride: BidirectionalCollection
223268
}
224269
}
225270

226-
extension Stride: RandomAccessCollection where Base: RandomAccessCollection {}
271+
extension StrideCollection: RandomAccessCollection where Base: RandomAccessCollection {}
227272

228-
extension Stride: Equatable where Base.Element: Equatable {
273+
extension StrideCollection: Equatable where Base.Element: Equatable {
229274
@inlinable
230-
public static func == (lhs: Stride, rhs: Stride) -> Bool {
275+
public static func == (lhs: StrideCollection, rhs: StrideCollection) -> Bool {
231276
lhs.elementsEqual(rhs, by: ==)
232277
}
233278
}
234279

235-
extension Stride: Hashable where Base.Element: Hashable {
280+
extension StrideCollection: Hashable where Base.Element: Hashable {
236281
@inlinable
237282
public func hash(into hasher: inout Hasher) {
238283
hasher.combine(stride)
@@ -242,4 +287,4 @@ extension Stride: Hashable where Base.Element: Hashable {
242287
}
243288
}
244289

245-
extension Stride.Index: Hashable where Base.Index: Hashable {}
290+
extension StrideCollection.Index: Hashable where Base.Index: Hashable {}

Tests/SwiftAlgorithmsTests/StrideTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ final class StridingTests: XCTestCase {
6868
let a = (0...10)
6969
XCTAssertEqualSequences(a.striding(by: 6), a.striding(by: 2).striding(by: 3))
7070
XCTAssertTrue(a.striding(by: 6) == a.striding(by: 2).striding(by: 3))
71-
XCTAssert(type(of: a.striding(by: 2).striding(by: 3)) == Stride<ClosedRange<Int>>.self)
71+
XCTAssert(type(of: a.striding(by: 2).striding(by: 3)) == StrideCollection<ClosedRange<Int>>.self)
7272
}
7373

7474
func testEquality() {

0 commit comments

Comments
 (0)