Files
swift-mirror/stdlib/public/core/RandomAccessCollection.swift
Dave Abrahams 0d68b3a4af [stdlib] Generate RandomAccessCollection defaults
The defaults we were generating for Collection and
BidirectionalCollection didn't make any sense, because if you could do
that strideable arithmetic then you essentially had random access.
Instead we constrain the defaults to apply to RandomAccessCollection
where the Indices are a CountableRange.
2016-05-02 11:35:32 -07:00

155 lines
5.1 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 collection that supports efficient random access index traversal.
///
/// - Important: In most cases, it's best to ignore this protocol and use
/// `RandomAccessCollection` instead, as it has a more complete interface.
public protocol RandomAccessIndexable : BidirectionalIndexable {
// 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.
}
/// A collection that supports efficient random access index traversal.
///
/// - Note: the fundamental difference between
/// `RandomAccessCollection` and `BidirectionalCollection` is that
/// the following are O(N) in `BidirectionalCollection` but O(1) in
/// `RandomAccessCollection`:
///
/// - `c.count`
/// - `c.index(i, offsetBy: n)`
/// - `c.index(i, offsetBy: n, limitedBy: l)`
/// - `c.distance(from: i, to: j)`
public protocol RandomAccessCollection :
RandomAccessIndexable, BidirectionalCollection
{
associatedtype SubSequence : RandomAccessIndexable, BidirectionalCollection
= RandomAccessSlice<Self>
// FIXME(compiler limitation):
// associatedtype SubSequence : RandomAccessCollection
associatedtype Indices : RandomAccessIndexable, BidirectionalCollection
= DefaultRandomAccessIndices<Self>
// FIXME(compiler limitation):
// associatedtype Indices : RandomAccessCollection
}
/// Supply the default "slicing" `subscript` for `RandomAccessCollection`
/// models that accept the default associated `SubSequence`,
/// `RandomAccessSlice<Self>`.
extension RandomAccessCollection where SubSequence == RandomAccessSlice<Self> {
public subscript(bounds: Range<Index>) -> RandomAccessSlice<Self> {
_failEarlyRangeCheck(bounds, bounds: startIndex..<endIndex)
return RandomAccessSlice(base: self, bounds: bounds)
}
}
// TODO: swift-3-indexing-model - Make sure RandomAccessCollection has
// documented complexity guarantees, e.g. for index(_:offsetBy:).
// TODO: swift-3-indexing-model - (By creating an ambiguity?), try to
// make sure RandomAccessCollection models implement
// index(_:offsetBy:) and distance(from:to:), or they will get the
// wrong complexity.
/// Default implementation for random access collections.
extension RandomAccessIndexable {
/// Returns the result of advancing `i` by `n` positions, or `nil`
/// if doing so would pass `limit`.
///
/// - Returns:
/// - `nil` if `(limit > i) == (n > 0) && abs(distance(i, limit)) < abs(n)`
/// - Otherwise, `index(i, offsetBy: n)`
///
/// - Complexity:
/// - O(1)
@warn_unused_result
func index(
i: Index, offsetBy n: IndexDistance, limitedBy limit: Index
) -> Index? {
let l = distance(from: i, to: limit)
if n > 0 ? l > 0 && l < n : l <= 0 && n < l {
return nil
}
return index(i, offsetBy: n)
}
}
extension RandomAccessCollection
where Index : Strideable,
Index.Stride == IndexDistance,
Indices == CountableRange<Index> {
public var indices: CountableRange<Index> {
return startIndex..<endIndex
}
internal func _validityChecked(_ i: Index) -> Index {
precondition(i >= startIndex && i <= endIndex, "index out of range")
return i
}
/// Returns the position immediately after `i`.
///
/// - Precondition: `(startIndex..<endIndex).contains(i)`
@warn_unused_result
public func index(after i: Index) -> Index {
return _validityChecked(i.advanced(by: 1))
}
/// Returns the position immediately preceding `i`.
///
/// - If `i >= startIndex && i < endIndex`,
/// `index(before: index(after: i)) == i`.
///
/// - If `i > startIndex && i <= endIndex`
/// `index(after: index(before: i)) == i`.
///
/// - Precondition: `i > startIndex && i <= endIndex`
@warn_unused_result
public func index(before i: Index) -> Index {
return _validityChecked(i.advanced(by: -1))
}
/// Returns the result of advancing `i` by `n` positions.
///
/// - Returns:
/// - If `n > 0`, the `n`th successor of `i`.
/// - If `n < 0`, the `n`th predecessor of `i`.
/// - Otherwise, `i` unmodified.
///
/// - Precondition:
/// - If `n > 0`, `n <= self.distance(from: i, to: self.endIndex)`
/// - If `n < 0`, `n >= self.distance(from: i, to: self.startIndex)`
///
/// - Complexity: O(1)
@warn_unused_result
public func index(_ i: Index, offsetBy n: Index.Stride) -> Index {
return _validityChecked(i.advanced(by: n))
}
/// Returns the distance from `start` to `end`.
///
/// - Complexity: O(1)
@warn_unused_result
public func distance(from start: Index, to end: Index) -> Index.Stride {
return start.distance(to: end)
}
}