Skip to content

[stdlib] Custom distance(from:to:) for LazyFilterCollection #13372

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,11 @@ extension TestSuite {
.forEach(in: distanceFromToTests) {
test in
let c = toCollection(0..<20)
let backwards = (test.startOffset > test.endOffset)
if backwards && !collectionIsBidirectional {
expectCrashLater()
}

let d = c.distance(
from: c.nthIndex(test.startOffset), to: c.nthIndex(test.endOffset))
expectEqual(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,8 @@ public struct ${Self}<T> : ${SelfProtocols} {
public func distance(from start: ${Index}, to end: ${Index})
-> Int {
% if Traversal == 'Forward':
_precondition(start <= end,
"Only BidirectionalCollections can have end come before start")
% end
// FIXME: swift-3-indexing-model: perform a range check properly.
if start != endIndex {
Expand Down
37 changes: 19 additions & 18 deletions stdlib/public/core/Collection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -701,11 +701,16 @@ public protocol Collection: Sequence where SubSequence: Collection {

/// Returns the distance between two indices.
///
/// Unless the collection conforms to the `BidirectionalCollection` protocol,
/// `start` must be less than or equal to `end`.
///
/// - Parameters:
/// - start: A valid index of the collection.
/// - end: Another valid index of the collection. If `end` is equal to
/// `start`, the result is zero.
/// - Returns: The distance between `start` and `end`.
/// - Returns: The distance between `start` and `end`. The result can be
/// negative only if the collection conforms to the
/// `BidirectionalCollection` protocol.
///
/// - Complexity: O(1) if the collection conforms to
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the
Expand Down Expand Up @@ -957,34 +962,30 @@ extension Collection {

/// Returns the distance between two indices.
///
/// Unless the collection conforms to the `BidirectionalCollection` protocol,
/// `start` must be less than or equal to `end`.
///
/// - Parameters:
/// - start: A valid index of the collection.
/// - end: Another valid index of the collection. If `end` is equal to
/// `start`, the result is zero.
/// - Returns: The distance between `start` and `end`.
/// - Returns: The distance between `start` and `end`. The result can be
/// negative only if the collection conforms to the
/// `BidirectionalCollection` protocol.
///
/// - Complexity: O(1) if the collection conforms to
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the
/// resulting distance.
@_inlineable
public func distance(from start: Index, to end: Index) -> Int {
var _start: Index
let _end: Index
let step: Int
if start > end {
_start = end
_end = start
step = -1
}
else {
_start = start
_end = end
step = 1
}
_precondition(start <= end,
"Only BidirectionalCollections can have end come before start")

var start = start
var count = 0
while _start != _end {
count += step
formIndex(after: &_start)
while start != end {
count = count + 1
formIndex(after: &start)
}
return count
}
Expand Down
27 changes: 27 additions & 0 deletions stdlib/public/core/Filter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,33 @@ extension LazyFilterCollection : LazyCollectionProtocol, Collection {
}
}

@_inlineable // FIXME(sil-serialize-all)
public func distance(from start: Index, to end: Index) -> Int {
// The following line makes sure that distance(from:to:) is invoked on the
// _base at least once, to trigger a _precondition in forward only
// collections.
_ = _base.distance(from: start, to: end)
var _start: Index
let _end: Index
let step: Int
if start > end {
_start = end
_end = start
step = -1
}
else {
_start = start
_end = end
step = 1
}
var count = 0
while _start != _end {
count += step
formIndex(after: &_start)
}
return count
}

@_inlineable // FIXME(sil-serialize-all)
public func index(_ i: Index, offsetBy n: Int) -> Index {
var i = i
Expand Down