Skip to content

[stdlib] Update complexity docs for seq/collection algorithms #17254

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

Merged
merged 7 commits into from
Jul 24, 2018
Merged
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
72 changes: 39 additions & 33 deletions stdlib/public/core/Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -429,24 +429,25 @@ extension Array: RandomAccessCollection, MutableCollection {
/// print(numbers[i])
/// // Prints "50"
///
/// The value passed as `n` must not offset `i` beyond the bounds of the
/// collection.
/// The value passed as `distance` must not offset `i` beyond the bounds of
/// the collection.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a. Shouldn't this be listed as a precondition?
b. The phrasing is a bit weird, since the value passed doesn't itself offset anything. Can we do better?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! I'm going to take this up on a different branch, since that's existing language and this branch keeps falling behind master.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@natecook1000 Looks like this was never resolved; master still contains this language.

///
/// - Parameters:
/// - i: A valid index of the array.
/// - n: The distance to offset `i`.
/// - Returns: An index offset by `n` from the index `i`. If `n` is positive,
/// this is the same value as the result of `n` calls to `index(after:)`.
/// If `n` is negative, this is the same value as the result of `-n` calls
/// to `index(before:)`.
/// - distance: The distance to offset `i`.
/// - Returns: An index offset by `distance` from the index `i`. If
/// `distance` is positive, this is the same value as the result of
/// `distance` calls to `index(after:)`. If `distance` is negative, this
/// is the same value as the result of `abs(distance)` calls to
/// `index(before:)`.
@inlinable
public func index(_ i: Int, offsetBy n: Int) -> Int {
public func index(_ i: Int, offsetBy distance: Int) -> Int {
// NOTE: this is a manual specialization of index movement for a Strideable
// index that is required for Array performance. The optimizer is not
// capable of creating partial specializations yet.
// NOTE: Range checks are not performed here, because it is done later by
// the subscript function.
return i + n
return i + distance
}

/// Returns an index that is the specified distance from the given index,
Expand Down Expand Up @@ -475,33 +476,36 @@ extension Array: RandomAccessCollection, MutableCollection {
/// print(j)
/// // Prints "nil"
///
/// The value passed as `n` must not offset `i` beyond the bounds of the
/// collection, unless the index passed as `limit` prevents offsetting
/// The value passed as `distance` must not offset `i` beyond the bounds of
/// the collection, unless the index passed as `limit` prevents offsetting
/// beyond those bounds.
///
/// - Parameters:
/// - i: A valid index of the array.
/// - n: The distance to offset `i`.
/// - limit: A valid index of the collection to use as a limit. If `n > 0`,
/// `limit` has no effect if it is less than `i`. Likewise, if `n < 0`,
/// `limit` has no effect if it is greater than `i`.
/// - Returns: An index offset by `n` from the index `i`, unless that index
/// would be beyond `limit` in the direction of movement. In that case,
/// the method returns `nil`.
/// - distance: The distance to offset `i`.
/// - limit: A valid index of the collection to use as a limit. If
/// `distance > 0`, `limit` has no effect if it is less than `i`.
/// Likewise, if `distance < 0`, `limit` has no effect if it is greater
/// than `i`.
/// - Returns: An index offset by `distance` from the index `i`, unless that
/// index would be beyond `limit` in the direction of movement. In that
/// case, the method returns `nil`.
///
/// - Complexity: O(1)
@inlinable
public func index(
_ i: Int, offsetBy n: Int, limitedBy limit: Int
_ i: Int, offsetBy distance: Int, limitedBy limit: Int
) -> Int? {
// NOTE: this is a manual specialization of index movement for a Strideable
// index that is required for Array performance. The optimizer is not
// capable of creating partial specializations yet.
// NOTE: Range checks are not performed here, because it is done later by
// the subscript function.
let l = limit - i
if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
if distance > 0 ? l >= 0 && l < distance : l <= 0 && distance < l {
return nil
}
return i + n
return i + distance
}

/// Returns the distance between two indices.
Expand Down Expand Up @@ -546,10 +550,9 @@ extension Array: RandomAccessCollection, MutableCollection {
/// greater than or equal to `startIndex` and less than `endIndex`.
///
/// - Complexity: Reading an element from an array is O(1). Writing is O(1)
/// unless the array's storage is shared with another array, in which case
/// writing is O(*n*), where *n* is the length of the array.
/// If the array uses a bridged `NSArray` instance as its storage, the
/// efficiency is unspecified.
/// unless the array's storage is shared with another array or uses a
/// bridged `NSArray` instance as its storage, in which case writing is
/// O(*n*), where *n* is the length of the array.
@inlinable
public subscript(index: Int) -> Element {
get {
Expand Down Expand Up @@ -1139,9 +1142,8 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
///
/// - Parameter newElement: The element to append to the array.
///
/// - Complexity: Amortized O(1) over many additions. If the array uses a
/// bridged `NSArray` instance as its storage, the efficiency is
/// unspecified.
/// - Complexity: O(1) on average, over many calls to `append(_:)` on the
/// same array.
@inlinable
@_semantics("array.append_element")
public mutating func append(_ newElement: Element) {
Expand All @@ -1164,7 +1166,9 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
///
/// - Parameter newElements: The elements to append to the array.
///
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
/// - Complexity: O(*m*) on average, where *m* is the length of
/// `newElements`, over many calls to `append(contentsOf:)` on the same
/// array.
@inlinable
@_semantics("array.append_contentsOf")
public mutating func append<S: Sequence>(contentsOf newElements: S)
Expand Down Expand Up @@ -1269,7 +1273,8 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
/// `index` must be a valid index of the array or equal to its `endIndex`
/// property.
///
/// - Complexity: O(*n*), where *n* is the length of the array.
/// - Complexity: O(*n*), where *n* is the length of the array. If
/// `i == endIndex`, this method is equivalent to `append(_:)`.
@inlinable
public mutating func insert(_ newElement: Element, at i: Int) {
_checkIndex(i)
Expand Down Expand Up @@ -1578,9 +1583,10 @@ extension Array {
/// a subrange must be valid indices of the array.
/// - newElements: The new elements to add to the array.
///
/// - Complexity: O(`subrange.count`) if you are replacing a suffix of the
/// array with an empty collection; otherwise, O(*n*), where *n* is the
/// length of the array.
/// - Complexity: O(*n* + *m*), where *n* is length of the array and
/// *m* is the length of `newElements`. If the call to this method simply
/// appends the contents of `newElements` to the array, this method is
/// equivalent to `append(contentsOf:)`.
@inlinable
@_semantics("array.mutate_unknown")
public mutating func replaceSubrange<C>(
Expand Down
74 changes: 43 additions & 31 deletions stdlib/public/core/ArraySlice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {

/// The position of the first element in a nonempty array.
///
/// `ArraySlice` instances are not always indexed from zero. Use `startIndex`
/// and `endIndex` as the bounds for any element access, instead of `0` and
/// `count`.
///
/// If the array is empty, `startIndex` is equal to `endIndex`.
@inlinable
public var startIndex: Int {
Expand Down Expand Up @@ -248,24 +252,25 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {
/// print(numbers[i])
/// // Prints "50"
///
/// The value passed as `n` must not offset `i` beyond the bounds of the
/// collection.
/// The value passed as `distance` must not offset `i` beyond the bounds of
/// the collection.
///
/// - Parameters:
/// - i: A valid index of the array.
/// - n: The distance to offset `i`.
/// - Returns: An index offset by `n` from the index `i`. If `n` is positive,
/// this is the same value as the result of `n` calls to `index(after:)`.
/// If `n` is negative, this is the same value as the result of `-n` calls
/// to `index(before:)`.
/// - distance: The distance to offset `i`.
/// - Returns: An index offset by `distance` from the index `i`. If
/// `distance` is positive, this is the same value as the result of
/// `distance` calls to `index(after:)`. If `distance` is negative, this
/// is the same value as the result of `abs(distance)` calls to
/// `index(before:)`.
@inlinable
public func index(_ i: Int, offsetBy n: Int) -> Int {
public func index(_ i: Int, offsetBy distance: Int) -> Int {
// NOTE: this is a manual specialization of index movement for a Strideable
// index that is required for Array performance. The optimizer is not
// capable of creating partial specializations yet.
// NOTE: Range checks are not performed here, because it is done later by
// the subscript function.
return i + n
return i + distance
}

/// Returns an index that is the specified distance from the given index,
Expand Down Expand Up @@ -294,33 +299,36 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {
/// print(j)
/// // Prints "nil"
///
/// The value passed as `n` must not offset `i` beyond the bounds of the
/// collection, unless the index passed as `limit` prevents offsetting
/// The value passed as `distance` must not offset `i` beyond the bounds of
/// the collection, unless the index passed as `limit` prevents offsetting
/// beyond those bounds.
///
/// - Parameters:
/// - i: A valid index of the array.
/// - n: The distance to offset `i`.
/// - limit: A valid index of the collection to use as a limit. If `n > 0`,
/// `limit` has no effect if it is less than `i`. Likewise, if `n < 0`,
/// `limit` has no effect if it is greater than `i`.
/// - Returns: An index offset by `n` from the index `i`, unless that index
/// would be beyond `limit` in the direction of movement. In that case,
/// the method returns `nil`.
/// - distance: The distance to offset `i`.
/// - limit: A valid index of the collection to use as a limit. If
/// `distance > 0`, `limit` has no effect if it is less than `i`.
/// Likewise, if `distance < 0`, `limit` has no effect if it is greater
/// than `i`.
/// - Returns: An index offset by `distance` from the index `i`, unless that
/// index would be beyond `limit` in the direction of movement. In that
/// case, the method returns `nil`.
///
/// - Complexity: O(1)
@inlinable
public func index(
_ i: Int, offsetBy n: Int, limitedBy limit: Int
_ i: Int, offsetBy distance: Int, limitedBy limit: Int
) -> Int? {
// NOTE: this is a manual specialization of index movement for a Strideable
// index that is required for Array performance. The optimizer is not
// capable of creating partial specializations yet.
// NOTE: Range checks are not performed here, because it is done later by
// the subscript function.
let l = limit - i
if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
if distance > 0 ? l >= 0 && l < distance : l <= 0 && distance < l {
return nil
}
return i + n
return i + distance
}

/// Returns the distance between two indices.
Expand Down Expand Up @@ -365,8 +373,9 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {
/// greater than or equal to `startIndex` and less than `endIndex`.
///
/// - Complexity: Reading an element from an array is O(1). Writing is O(1)
/// unless the array's storage is shared with another array, in which case
/// writing is O(*n*), where *n* is the length of the array.
/// unless the array's storage is shared with another array or uses a
/// bridged `NSArray` instance as its storage, in which case writing is
/// O(*n*), where *n* is the length of the array.
@inlinable
public subscript(index: Int) -> Element {
get {
Expand Down Expand Up @@ -931,9 +940,8 @@ extension ArraySlice: RangeReplaceableCollection, ArrayProtocol {
///
/// - Parameter newElement: The element to append to the array.
///
/// - Complexity: Amortized O(1) over many additions. If the array uses a
/// bridged `NSArray` instance as its storage, the efficiency is
/// unspecified.
/// - Complexity: O(1) on average, over many calls to `append(_:)` on the
/// same array.
@inlinable
@_semantics("array.append_element")
public mutating func append(_ newElement: Element) {
Expand All @@ -956,7 +964,9 @@ extension ArraySlice: RangeReplaceableCollection, ArrayProtocol {
///
/// - Parameter newElements: The elements to append to the array.
///
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
/// - Complexity: O(*m*) on average, where *m* is the length of
/// `newElements`, over many calls to `append(contentsOf:)` on the same
/// array.
@inlinable
@_semantics("array.append_contentsOf")
public mutating func append<S: Sequence>(contentsOf newElements: S)
Expand Down Expand Up @@ -1061,7 +1071,8 @@ extension ArraySlice: RangeReplaceableCollection, ArrayProtocol {
/// `index` must be a valid index of the array or equal to its `endIndex`
/// property.
///
/// - Complexity: O(*n*), where *n* is the length of the array.
/// - Complexity: O(*n*), where *n* is the length of the array. If
/// `i == endIndex`, this method is equivalent to `append(_:)`.
@inlinable
public mutating func insert(_ newElement: Element, at i: Int) {
_checkIndex(i)
Expand Down Expand Up @@ -1320,9 +1331,10 @@ extension ArraySlice {
/// a subrange must be valid indices of the array.
/// - newElements: The new elements to add to the array.
///
/// - Complexity: O(`subrange.count`) if you are replacing a suffix of the
/// array with an empty collection; otherwise, O(*n*), where *n* is the
/// length of the array.
/// - Complexity: O(*n* + *m*), where *n* is length of the array and
/// *m* is the length of `newElements`. If the call to this method simply
/// appends the contents of `newElements` to the array, this method is
/// equivalent to `append(contentsOf:)`.
@inlinable
@_semantics("array.mutate_unknown")
public mutating func replaceSubrange<C>(
Expand Down
Loading