mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
269 lines
8.0 KiB
Swift
269 lines
8.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A type that provides subscript access to its elements, with
|
|
/// bidirectional index traversal.
|
|
///
|
|
/// - Important: In most cases, it's best to ignore this protocol and use
|
|
/// `BidirectionalCollection` instead, as it has a more complete interface.
|
|
public protocol BidirectionalIndexable : Indexable {
|
|
// FIXME(ABI)(compiler limitation): there is no reason for this protocol
|
|
// to exist apart from missing compiler features that we emulate with it.
|
|
//
|
|
// This protocol is almost an implementation detail of the standard
|
|
// library.
|
|
|
|
/// Returns the position immediately preceding `i`.
|
|
///
|
|
/// - If `i >= startIndex && i < endIndex`,
|
|
/// `predecessor(of: successor(of: i)) == i`.
|
|
///
|
|
/// - If `i > startIndex && i <= endIndex`
|
|
/// `successor(of: predecessor(of: i)) == i`.
|
|
///
|
|
/// - Precondition: `i > startIndex && i <= endIndex`
|
|
@warn_unused_result
|
|
func predecessor(of i: Index) -> Index
|
|
|
|
/// Replaces `i` with its predecessor.
|
|
func formPredecessor(_ i: inout Index)
|
|
}
|
|
|
|
/// A collection that supports backward as well as forward traversal.
|
|
///
|
|
/// For any index `i` into a bidirectional collection `c`:
|
|
///
|
|
/// - If `i >= c.startIndex && i < c.endIndex`,
|
|
/// `c.predecessor(of: c.successor(of: i)) == i`.
|
|
///
|
|
/// - If `i > c.startIndex && i <= c.endIndex`
|
|
/// `c.successor(of: c.predecessor(of: i)) == i`.
|
|
public protocol BidirectionalCollection
|
|
: BidirectionalIndexable, Collection {
|
|
|
|
// TODO: swift-3-indexing-model - replaces functionality in BidirectionalIndex
|
|
/// Returns the position immediately preceding `i`.
|
|
///
|
|
/// - Precondition: `i > startIndex && i <= endIndex`
|
|
@warn_unused_result
|
|
func predecessor(of i: Index) -> Index
|
|
|
|
/// Replaces `i` with its predecessor.
|
|
///
|
|
/// - Precondition: `i > startIndex && i <= endIndex`
|
|
func formPredecessor(_ i: inout Index)
|
|
|
|
associatedtype SubSequence : BidirectionalIndexable, Collection
|
|
= BidirectionalSlice<Self>
|
|
// FIXME(compiler limitation):
|
|
// associatedtype SubSequence : BidirectionalCollection
|
|
|
|
associatedtype Indices : BidirectionalIndexable, Collection
|
|
= DefaultBidirectionalIndices<Self>
|
|
// FIXME(compiler limitation):
|
|
// associatedtype Indices : BidirectionalCollection
|
|
|
|
// TODO: swift-3-indexing-model: tests.
|
|
/// The last element of `self`, or `nil` if `self` is empty.
|
|
var last: Iterator.Element? { get }
|
|
}
|
|
|
|
/// Default implementation for bidirectional collections.
|
|
extension BidirectionalIndexable {
|
|
|
|
@inline(__always)
|
|
public func formPredecessor(_ i: inout Index) {
|
|
i = predecessor(of: i)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func index(_ n: IndexDistance, stepsFrom i: Index) -> Index {
|
|
if n >= 0 {
|
|
return _advanceForward(i, by: n)
|
|
}
|
|
var i = i
|
|
for _ in stride(from: 0, to: n, by: -1) {
|
|
formPredecessor(&i)
|
|
}
|
|
return i
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func index(
|
|
_ n: IndexDistance, stepsFrom i: Index, limitedBy limit: Index
|
|
) -> Index? {
|
|
if n >= 0 {
|
|
return _advanceForward(i, by: n, limitedBy: limit)
|
|
}
|
|
var i = i
|
|
for _ in stride(from: 0, to: n, by: -1) {
|
|
if i == limit {
|
|
return nil
|
|
}
|
|
formPredecessor(&i)
|
|
}
|
|
return i
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func distance(from start: Index, to end: Index) -> IndexDistance {
|
|
var start = start
|
|
var count: IndexDistance = 0
|
|
|
|
if start < end {
|
|
while start != end {
|
|
count += 1 as IndexDistance
|
|
formSuccessor(&start)
|
|
}
|
|
}
|
|
else if start > end {
|
|
while start != end {
|
|
count -= 1 as IndexDistance
|
|
formPredecessor(&start)
|
|
}
|
|
}
|
|
|
|
return count
|
|
}
|
|
}
|
|
|
|
/// Supply optimized defaults for `BidirectionalCollection` models that use
|
|
/// some model of `Strideable` as their `Index`.
|
|
extension BidirectionalIndexable
|
|
where
|
|
Index : Strideable,
|
|
Index.Stride == IndexDistance,
|
|
Index.Stride : SignedInteger {
|
|
|
|
@warn_unused_result
|
|
public func predecessor(of i: Index) -> Index {
|
|
// FIXME: swift-3-indexing-model: range check i: should allow `endIndex`.
|
|
//_failEarlyRangeCheck(i, bounds: startIndex..<endIndex)
|
|
|
|
return i.advanced(by: -1)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func index(_ n: IndexDistance, stepsFrom i: Index) -> Index {
|
|
// FIXME: swift-3-indexing-model: range check i
|
|
return i.advanced(by: n)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func index(
|
|
_ n: IndexDistance, stepsFrom i: Index, limitedBy limit: Index
|
|
) -> Index? {
|
|
// FIXME: swift-3-indexing-model: range check i
|
|
if n == 0 {
|
|
return i
|
|
}
|
|
let i = i.advanced(by: n)
|
|
if (n > 0) ? (i > limit) : (i < limit) {
|
|
return nil
|
|
}
|
|
return i
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func distance(from start: Index, to end: Index) -> IndexDistance {
|
|
// FIXME: swift-3-indexing-model: range check supplies start and end?
|
|
return start.distance(to: end)
|
|
}
|
|
}
|
|
|
|
/// Supply the default "slicing" `subscript` for `BidirectionalCollection`
|
|
/// models that accept the default associated `SubSequence`,
|
|
/// `BidirectionalSlice<Self>`.
|
|
extension BidirectionalIndexable where SubSequence == BidirectionalSlice<Self> {
|
|
public subscript(bounds: Range<Index>) -> BidirectionalSlice<Self> {
|
|
_failEarlyRangeCheck(bounds, bounds: startIndex..<endIndex)
|
|
return BidirectionalSlice(base: self, bounds: bounds)
|
|
}
|
|
}
|
|
|
|
extension BidirectionalCollection where SubSequence == Self {
|
|
/// If `!self.isEmpty`, remove the last element and return it, otherwise
|
|
/// return `nil`.
|
|
///
|
|
/// - Complexity: O(1)
|
|
@warn_unused_result
|
|
public mutating func popLast() -> Iterator.Element? {
|
|
guard !isEmpty else { return nil }
|
|
let element = last!
|
|
self = self[startIndex..<predecessor(of: endIndex)]
|
|
return element
|
|
}
|
|
|
|
/// Remove an element from the end.
|
|
///
|
|
/// - Complexity: O(1)
|
|
/// - Precondition: `!self.isEmpty`
|
|
@discardableResult
|
|
public mutating func removeLast() -> Iterator.Element {
|
|
let element = last!
|
|
self = self[startIndex..<predecessor(of: endIndex)]
|
|
return element
|
|
}
|
|
|
|
/// Remove the last `n` elements.
|
|
///
|
|
/// - Complexity:
|
|
/// - O(1) if `Self` conforms to `RandomAccessCollection`
|
|
/// - O(n) otherwise
|
|
/// - Precondition: `n >= 0 && self.count >= n`.
|
|
public mutating func removeLast(_ n: Int) {
|
|
if n == 0 { return }
|
|
_precondition(n >= 0, "number of elements to remove should be non-negative")
|
|
_precondition(count >= numericCast(n),
|
|
"can't remove more items from a collection than it contains")
|
|
self = self[startIndex..<index(numericCast(-n), stepsFrom: endIndex)]
|
|
}
|
|
}
|
|
|
|
extension BidirectionalCollection {
|
|
/// Returns a subsequence containing all but the last `n` elements.
|
|
///
|
|
/// - Precondition: `n >= 0`
|
|
/// - Complexity: O(`n`)
|
|
@warn_unused_result
|
|
public func dropLast(_ n: Int) -> SubSequence {
|
|
_precondition(
|
|
n >= 0, "Can't drop a negative number of elements from a collection")
|
|
let end = index(
|
|
numericCast(-n),
|
|
stepsFrom: endIndex,
|
|
limitedBy: startIndex) ?? startIndex
|
|
return self[startIndex..<end]
|
|
}
|
|
|
|
/// Returns a slice, up to `maxLength` in length, containing the
|
|
/// final elements of `self`.
|
|
///
|
|
/// If `maxLength` exceeds `s.count`, the result contains all
|
|
/// the elements of `self`.
|
|
///
|
|
/// - Precondition: `maxLength >= 0`
|
|
/// - Complexity: O(`maxLength`)
|
|
@warn_unused_result
|
|
public func suffix(_ maxLength: Int) -> SubSequence {
|
|
_precondition(
|
|
maxLength >= 0,
|
|
"Can't take a suffix of negative length from a collection")
|
|
let start = index(
|
|
numericCast(-maxLength),
|
|
stepsFrom: endIndex,
|
|
limitedBy: startIndex) ?? startIndex
|
|
return self[start..<endIndex]
|
|
}
|
|
}
|
|
|