Skip to content

Commit 3d7dfc2

Browse files
authored
[stdlib] Update complexity docs for seq/collection algorithms (#17254)
* [stdlib] Update complexity docs for seq/collection algorithms This corrects and standardizes the complexity documentation for Sequence and Collection methods. The use of constants is more consistent, with `n` equal to the length of the target collection, `m` equal to the length of a collection passed in as a parameter, and `k` equal to any other passed or calculated constant. * Apply notes from @brentdax about complexity nomenclature * Change `n` to `distance` in `index(_:offsetBy:)` * Use equivalency language more places; sync across array types * Use k instead of n for parameter names * Slight changes to index(_:offsetBy:) discussion. * Update tests with new parameter names
1 parent 0abb019 commit 3d7dfc2

16 files changed

+552
-393
lines changed

stdlib/public/core/Array.swift

+39-33
Original file line numberDiff line numberDiff line change
@@ -429,24 +429,25 @@ extension Array: RandomAccessCollection, MutableCollection {
429429
/// print(numbers[i])
430430
/// // Prints "50"
431431
///
432-
/// The value passed as `n` must not offset `i` beyond the bounds of the
433-
/// collection.
432+
/// The value passed as `distance` must not offset `i` beyond the bounds of
433+
/// the collection.
434434
///
435435
/// - Parameters:
436436
/// - i: A valid index of the array.
437-
/// - n: The distance to offset `i`.
438-
/// - Returns: An index offset by `n` from the index `i`. If `n` is positive,
439-
/// this is the same value as the result of `n` calls to `index(after:)`.
440-
/// If `n` is negative, this is the same value as the result of `-n` calls
441-
/// to `index(before:)`.
437+
/// - distance: The distance to offset `i`.
438+
/// - Returns: An index offset by `distance` from the index `i`. If
439+
/// `distance` is positive, this is the same value as the result of
440+
/// `distance` calls to `index(after:)`. If `distance` is negative, this
441+
/// is the same value as the result of `abs(distance)` calls to
442+
/// `index(before:)`.
442443
@inlinable
443-
public func index(_ i: Int, offsetBy n: Int) -> Int {
444+
public func index(_ i: Int, offsetBy distance: Int) -> Int {
444445
// NOTE: this is a manual specialization of index movement for a Strideable
445446
// index that is required for Array performance. The optimizer is not
446447
// capable of creating partial specializations yet.
447448
// NOTE: Range checks are not performed here, because it is done later by
448449
// the subscript function.
449-
return i + n
450+
return i + distance
450451
}
451452

452453
/// Returns an index that is the specified distance from the given index,
@@ -475,33 +476,36 @@ extension Array: RandomAccessCollection, MutableCollection {
475476
/// print(j)
476477
/// // Prints "nil"
477478
///
478-
/// The value passed as `n` must not offset `i` beyond the bounds of the
479-
/// collection, unless the index passed as `limit` prevents offsetting
479+
/// The value passed as `distance` must not offset `i` beyond the bounds of
480+
/// the collection, unless the index passed as `limit` prevents offsetting
480481
/// beyond those bounds.
481482
///
482483
/// - Parameters:
483484
/// - i: A valid index of the array.
484-
/// - n: The distance to offset `i`.
485-
/// - limit: A valid index of the collection to use as a limit. If `n > 0`,
486-
/// `limit` has no effect if it is less than `i`. Likewise, if `n < 0`,
487-
/// `limit` has no effect if it is greater than `i`.
488-
/// - Returns: An index offset by `n` from the index `i`, unless that index
489-
/// would be beyond `limit` in the direction of movement. In that case,
490-
/// the method returns `nil`.
485+
/// - distance: The distance to offset `i`.
486+
/// - limit: A valid index of the collection to use as a limit. If
487+
/// `distance > 0`, `limit` has no effect if it is less than `i`.
488+
/// Likewise, if `distance < 0`, `limit` has no effect if it is greater
489+
/// than `i`.
490+
/// - Returns: An index offset by `distance` from the index `i`, unless that
491+
/// index would be beyond `limit` in the direction of movement. In that
492+
/// case, the method returns `nil`.
493+
///
494+
/// - Complexity: O(1)
491495
@inlinable
492496
public func index(
493-
_ i: Int, offsetBy n: Int, limitedBy limit: Int
497+
_ i: Int, offsetBy distance: Int, limitedBy limit: Int
494498
) -> Int? {
495499
// NOTE: this is a manual specialization of index movement for a Strideable
496500
// index that is required for Array performance. The optimizer is not
497501
// capable of creating partial specializations yet.
498502
// NOTE: Range checks are not performed here, because it is done later by
499503
// the subscript function.
500504
let l = limit - i
501-
if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
505+
if distance > 0 ? l >= 0 && l < distance : l <= 0 && distance < l {
502506
return nil
503507
}
504-
return i + n
508+
return i + distance
505509
}
506510

507511
/// Returns the distance between two indices.
@@ -546,10 +550,9 @@ extension Array: RandomAccessCollection, MutableCollection {
546550
/// greater than or equal to `startIndex` and less than `endIndex`.
547551
///
548552
/// - Complexity: Reading an element from an array is O(1). Writing is O(1)
549-
/// unless the array's storage is shared with another array, in which case
550-
/// writing is O(*n*), where *n* is the length of the array.
551-
/// If the array uses a bridged `NSArray` instance as its storage, the
552-
/// efficiency is unspecified.
553+
/// unless the array's storage is shared with another array or uses a
554+
/// bridged `NSArray` instance as its storage, in which case writing is
555+
/// O(*n*), where *n* is the length of the array.
553556
@inlinable
554557
public subscript(index: Int) -> Element {
555558
get {
@@ -1139,9 +1142,8 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
11391142
///
11401143
/// - Parameter newElement: The element to append to the array.
11411144
///
1142-
/// - Complexity: Amortized O(1) over many additions. If the array uses a
1143-
/// bridged `NSArray` instance as its storage, the efficiency is
1144-
/// unspecified.
1145+
/// - Complexity: O(1) on average, over many calls to `append(_:)` on the
1146+
/// same array.
11451147
@inlinable
11461148
@_semantics("array.append_element")
11471149
public mutating func append(_ newElement: Element) {
@@ -1164,7 +1166,9 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
11641166
///
11651167
/// - Parameter newElements: The elements to append to the array.
11661168
///
1167-
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
1169+
/// - Complexity: O(*m*) on average, where *m* is the length of
1170+
/// `newElements`, over many calls to `append(contentsOf:)` on the same
1171+
/// array.
11681172
@inlinable
11691173
@_semantics("array.append_contentsOf")
11701174
public mutating func append<S: Sequence>(contentsOf newElements: S)
@@ -1269,7 +1273,8 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
12691273
/// `index` must be a valid index of the array or equal to its `endIndex`
12701274
/// property.
12711275
///
1272-
/// - Complexity: O(*n*), where *n* is the length of the array.
1276+
/// - Complexity: O(*n*), where *n* is the length of the array. If
1277+
/// `i == endIndex`, this method is equivalent to `append(_:)`.
12731278
@inlinable
12741279
public mutating func insert(_ newElement: Element, at i: Int) {
12751280
_checkIndex(i)
@@ -1578,9 +1583,10 @@ extension Array {
15781583
/// a subrange must be valid indices of the array.
15791584
/// - newElements: The new elements to add to the array.
15801585
///
1581-
/// - Complexity: O(`subrange.count`) if you are replacing a suffix of the
1582-
/// array with an empty collection; otherwise, O(*n*), where *n* is the
1583-
/// length of the array.
1586+
/// - Complexity: O(*n* + *m*), where *n* is length of the array and
1587+
/// *m* is the length of `newElements`. If the call to this method simply
1588+
/// appends the contents of `newElements` to the array, this method is
1589+
/// equivalent to `append(contentsOf:)`.
15841590
@inlinable
15851591
@_semantics("array.mutate_unknown")
15861592
public mutating func replaceSubrange<C>(

stdlib/public/core/ArraySlice.swift

+43-31
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {
154154

155155
/// The position of the first element in a nonempty array.
156156
///
157+
/// `ArraySlice` instances are not always indexed from zero. Use `startIndex`
158+
/// and `endIndex` as the bounds for any element access, instead of `0` and
159+
/// `count`.
160+
///
157161
/// If the array is empty, `startIndex` is equal to `endIndex`.
158162
@inlinable
159163
public var startIndex: Int {
@@ -248,24 +252,25 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {
248252
/// print(numbers[i])
249253
/// // Prints "50"
250254
///
251-
/// The value passed as `n` must not offset `i` beyond the bounds of the
252-
/// collection.
255+
/// The value passed as `distance` must not offset `i` beyond the bounds of
256+
/// the collection.
253257
///
254258
/// - Parameters:
255259
/// - i: A valid index of the array.
256-
/// - n: The distance to offset `i`.
257-
/// - Returns: An index offset by `n` from the index `i`. If `n` is positive,
258-
/// this is the same value as the result of `n` calls to `index(after:)`.
259-
/// If `n` is negative, this is the same value as the result of `-n` calls
260-
/// to `index(before:)`.
260+
/// - distance: The distance to offset `i`.
261+
/// - Returns: An index offset by `distance` from the index `i`. If
262+
/// `distance` is positive, this is the same value as the result of
263+
/// `distance` calls to `index(after:)`. If `distance` is negative, this
264+
/// is the same value as the result of `abs(distance)` calls to
265+
/// `index(before:)`.
261266
@inlinable
262-
public func index(_ i: Int, offsetBy n: Int) -> Int {
267+
public func index(_ i: Int, offsetBy distance: Int) -> Int {
263268
// NOTE: this is a manual specialization of index movement for a Strideable
264269
// index that is required for Array performance. The optimizer is not
265270
// capable of creating partial specializations yet.
266271
// NOTE: Range checks are not performed here, because it is done later by
267272
// the subscript function.
268-
return i + n
273+
return i + distance
269274
}
270275

271276
/// Returns an index that is the specified distance from the given index,
@@ -294,33 +299,36 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {
294299
/// print(j)
295300
/// // Prints "nil"
296301
///
297-
/// The value passed as `n` must not offset `i` beyond the bounds of the
298-
/// collection, unless the index passed as `limit` prevents offsetting
302+
/// The value passed as `distance` must not offset `i` beyond the bounds of
303+
/// the collection, unless the index passed as `limit` prevents offsetting
299304
/// beyond those bounds.
300305
///
301306
/// - Parameters:
302307
/// - i: A valid index of the array.
303-
/// - n: The distance to offset `i`.
304-
/// - limit: A valid index of the collection to use as a limit. If `n > 0`,
305-
/// `limit` has no effect if it is less than `i`. Likewise, if `n < 0`,
306-
/// `limit` has no effect if it is greater than `i`.
307-
/// - Returns: An index offset by `n` from the index `i`, unless that index
308-
/// would be beyond `limit` in the direction of movement. In that case,
309-
/// the method returns `nil`.
308+
/// - distance: The distance to offset `i`.
309+
/// - limit: A valid index of the collection to use as a limit. If
310+
/// `distance > 0`, `limit` has no effect if it is less than `i`.
311+
/// Likewise, if `distance < 0`, `limit` has no effect if it is greater
312+
/// than `i`.
313+
/// - Returns: An index offset by `distance` from the index `i`, unless that
314+
/// index would be beyond `limit` in the direction of movement. In that
315+
/// case, the method returns `nil`.
316+
///
317+
/// - Complexity: O(1)
310318
@inlinable
311319
public func index(
312-
_ i: Int, offsetBy n: Int, limitedBy limit: Int
320+
_ i: Int, offsetBy distance: Int, limitedBy limit: Int
313321
) -> Int? {
314322
// NOTE: this is a manual specialization of index movement for a Strideable
315323
// index that is required for Array performance. The optimizer is not
316324
// capable of creating partial specializations yet.
317325
// NOTE: Range checks are not performed here, because it is done later by
318326
// the subscript function.
319327
let l = limit - i
320-
if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
328+
if distance > 0 ? l >= 0 && l < distance : l <= 0 && distance < l {
321329
return nil
322330
}
323-
return i + n
331+
return i + distance
324332
}
325333

326334
/// Returns the distance between two indices.
@@ -365,8 +373,9 @@ extension ArraySlice: RandomAccessCollection, MutableCollection {
365373
/// greater than or equal to `startIndex` and less than `endIndex`.
366374
///
367375
/// - Complexity: Reading an element from an array is O(1). Writing is O(1)
368-
/// unless the array's storage is shared with another array, in which case
369-
/// writing is O(*n*), where *n* is the length of the array.
376+
/// unless the array's storage is shared with another array or uses a
377+
/// bridged `NSArray` instance as its storage, in which case writing is
378+
/// O(*n*), where *n* is the length of the array.
370379
@inlinable
371380
public subscript(index: Int) -> Element {
372381
get {
@@ -931,9 +940,8 @@ extension ArraySlice: RangeReplaceableCollection, ArrayProtocol {
931940
///
932941
/// - Parameter newElement: The element to append to the array.
933942
///
934-
/// - Complexity: Amortized O(1) over many additions. If the array uses a
935-
/// bridged `NSArray` instance as its storage, the efficiency is
936-
/// unspecified.
943+
/// - Complexity: O(1) on average, over many calls to `append(_:)` on the
944+
/// same array.
937945
@inlinable
938946
@_semantics("array.append_element")
939947
public mutating func append(_ newElement: Element) {
@@ -956,7 +964,9 @@ extension ArraySlice: RangeReplaceableCollection, ArrayProtocol {
956964
///
957965
/// - Parameter newElements: The elements to append to the array.
958966
///
959-
/// - Complexity: O(*n*), where *n* is the length of the resulting array.
967+
/// - Complexity: O(*m*) on average, where *m* is the length of
968+
/// `newElements`, over many calls to `append(contentsOf:)` on the same
969+
/// array.
960970
@inlinable
961971
@_semantics("array.append_contentsOf")
962972
public mutating func append<S: Sequence>(contentsOf newElements: S)
@@ -1061,7 +1071,8 @@ extension ArraySlice: RangeReplaceableCollection, ArrayProtocol {
10611071
/// `index` must be a valid index of the array or equal to its `endIndex`
10621072
/// property.
10631073
///
1064-
/// - Complexity: O(*n*), where *n* is the length of the array.
1074+
/// - Complexity: O(*n*), where *n* is the length of the array. If
1075+
/// `i == endIndex`, this method is equivalent to `append(_:)`.
10651076
@inlinable
10661077
public mutating func insert(_ newElement: Element, at i: Int) {
10671078
_checkIndex(i)
@@ -1320,9 +1331,10 @@ extension ArraySlice {
13201331
/// a subrange must be valid indices of the array.
13211332
/// - newElements: The new elements to add to the array.
13221333
///
1323-
/// - Complexity: O(`subrange.count`) if you are replacing a suffix of the
1324-
/// array with an empty collection; otherwise, O(*n*), where *n* is the
1325-
/// length of the array.
1334+
/// - Complexity: O(*n* + *m*), where *n* is length of the array and
1335+
/// *m* is the length of `newElements`. If the call to this method simply
1336+
/// appends the contents of `newElements` to the array, this method is
1337+
/// equivalent to `append(contentsOf:)`.
13261338
@inlinable
13271339
@_semantics("array.mutate_unknown")
13281340
public mutating func replaceSubrange<C>(

0 commit comments

Comments
 (0)