Skip to content

Commit 0782b48

Browse files
committed
[stdlib] Documentation improvements
- Revise Equatable and Hashable for synthesized requirements - Complete Strideable and stride(from:...:by:) documentation - Revise DoubleWidth type docs - Add complexity notes for Set.index(of:) and .contains(_:) - Fix typos in Set.formUnion docs - Add missing axioms for SetAlgebra (SR-6319) - Improve guidance for description and debugDescription - Add note about the result of passing duplicate keys to Dictionary(uniqueKeysWithValues:) - Fix typo in BinaryInteger docs - Update Substring docs with better conversion example - Improve docs for withMemoryRebound and isKnownUniquelyReferenced - Add missing docs not propagated from protocols
1 parent e783bef commit 0782b48

22 files changed

+517
-79
lines changed

stdlib/public/core/DoubleWidth.swift.gyb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,38 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
/// A fixed-width integer that is twice the size of its base type.
14+
///
15+
/// You can use the `DoubleWidth` type to continue calculations with the result
16+
/// of a full width arithmetic operation. Normally, when you perform a full
17+
/// width operation, the result is a tuple of the high and low components of
18+
/// the result.
19+
///
20+
/// let a = 2241543570477705381
21+
/// let b = 186319822866995413
22+
/// let c = a.multipliedFullWidth(by: b)
23+
/// // c == (22640526660490081, 7959093232766896457)
24+
///
25+
/// The tuple `c` can't be used in any further comparisons or calculations. To
26+
/// use this value, create a `DoubleWidth` instance from the result. You can
27+
/// use the `DoubleWidth` instance the way you use any other integer type.
28+
///
29+
/// let d = DoubleWidth(a.multipliedFullWidth(by: b))
30+
/// // d == 417644001000058515200174966092417353
31+
///
32+
/// // Check the calculation:
33+
/// print(d / DoubleWidth(a) == b)
34+
/// // Prints "true"
35+
///
36+
/// if d > Int.max {
37+
/// print("Too big to be an 'Int'!")
38+
/// } else {
39+
/// print("Small enough to fit in an 'Int'")
40+
/// }
41+
/// // Prints "Too big to be an 'Int'!"
42+
///
43+
/// The `DoubleWidth` type is intended for intermediate calculations, not as a
44+
/// replacement for a variable-width integer type. Nesting `DoubleWidth`
45+
/// instances, in particular, can result in undesirable performance.
1446
@_fixed_layout // FIXME(sil-serialize-all)
1547
public struct DoubleWidth<Base : FixedWidthInteger>
1648
: _ExpressibleByBuiltinIntegerLiteral

stdlib/public/core/Equatable.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,28 @@
4848
/// `Comparable` protocols, which allow more uses of your custom type, such as
4949
/// constructing sets or sorting the elements of a collection.
5050
///
51-
/// To adopt the `Equatable` protocol, implement the equal-to operator (`==`)
52-
/// as a static method of your type. The standard library provides an
51+
/// You can rely on automatic synthesis of the `Equatable` protocol's
52+
/// requirements for a custom type when you declare `Equatable` conformance in
53+
/// the type's original declaration and your type meets these criteria:
54+
///
55+
/// - For a `struct`, all its stored properties must conform to `Equatable`.
56+
/// - For an `enum`, all its associated values must conform to `Equatable`. (An
57+
/// `enum` without associated values has `Equatable` conformance even
58+
/// without the declaration.)
59+
///
60+
/// To customize your type's `Equatable` conformance, to adopt `Equatable` in a
61+
/// type that doesn't meet the criteria listed above, or to extend an existing
62+
/// type to conform to `Equatable`, implement the equal-to operator (`==`) as
63+
/// a static method of your type. The standard library provides an
5364
/// implementation for the not-equal-to operator (`!=`) for any `Equatable`
5465
/// type, which calls the custom `==` function and negates its result.
5566
///
56-
/// As an example, consider a `StreetAddress` structure that holds the parts of
57-
/// a street address: a house or building number, the street name, and an
67+
/// As an example, consider a `StreetAddress` class that holds the parts of a
68+
/// street address: a house or building number, the street name, and an
5869
/// optional unit number. Here's the initial declaration of the
5970
/// `StreetAddress` type:
6071
///
61-
/// struct StreetAddress {
72+
/// class StreetAddress {
6273
/// let number: String
6374
/// let street: String
6475
/// let unit: String?
@@ -151,7 +162,7 @@
151162
/// triple-equals identical-to operator (`===`). For example:
152163
///
153164
/// let c = a
154-
/// print(a === c, b === c, separator: ", ")
165+
/// print(c === a, c === b, separator: ", ")
155166
/// // Prints "true, false"
156167
public protocol Equatable {
157168
/// Returns a Boolean value indicating whether two values are equal.

stdlib/public/core/FloatingPoint.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ public protocol FloatingPoint: SignedNumeric, Strideable, Hashable {
688688
///
689689
/// If this value and `other` are finite numbers, the remainder is in the
690690
/// closed range `-abs(other / 2)...abs(other / 2)`. The
691-
/// `remainder(dividingBy:)` method is always exact.
691+
/// `formRemainder(dividingBy:)` method is always exact.
692692
///
693693
/// - Parameter other: The value to use when dividing this value.
694694
mutating func formRemainder(dividingBy other: Self)

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,14 @@ extension ${Self} : CustomDebugStringConvertible {
109109

110110
extension ${Self}: BinaryFloatingPoint {
111111

112+
/// A type that can represent the absolute value of any possible value of
113+
/// this type.
112114
public typealias Magnitude = ${Self}
115+
116+
/// A type that can represent any written exponent.
113117
public typealias Exponent = Int
118+
119+
/// A type that represents the encoded significand of a value.
114120
public typealias RawSignificand = ${RawSignificand}
115121

116122
/// The number of bits used to represent the type's exponent.
@@ -980,6 +986,35 @@ extension ${Self}: BinaryFloatingPoint {
980986
lhs._value = Builtin.fdiv_FPIEEE${bits}(lhs._value, rhs._value)
981987
}
982988

989+
/// Replaces this value with the remainder of itself divided by the given
990+
/// value.
991+
///
992+
/// For two finite values `x` and `y`, the remainder `r` of dividing `x` by
993+
/// `y` satisfies `x == y * q + r`, where `q` is the integer nearest to
994+
/// `x / y`. If `x / y` is exactly halfway between two integers, `q` is
995+
/// chosen to be even. Note that `q` is *not* `x / y` computed in
996+
/// floating-point arithmetic, and that `q` may not be representable in any
997+
/// available integer type.
998+
///
999+
/// The following example calculates the remainder of dividing 8.625 by 0.75:
1000+
///
1001+
/// var x = 8.625
1002+
/// print(x / 0.75)
1003+
/// // Prints "11.5"
1004+
///
1005+
/// let q = (x / 0.75).rounded(.toNearestOrEven)
1006+
/// // q == 12.0
1007+
/// x.formRemainder(dividingBy: 0.75)
1008+
/// // x == -0.375
1009+
///
1010+
/// let x1 = 0.75 * q + x
1011+
/// // x1 == 8.625
1012+
///
1013+
/// If this value and `other` are finite numbers, the remainder is in the
1014+
/// closed range `-abs(other / 2)...abs(other / 2)`. The
1015+
/// `formRemainder(dividingBy:)` method is always exact.
1016+
///
1017+
/// - Parameter other: The value to use when dividing this value.
9831018
@_inlineable // FIXME(sil-serialize-all)
9841019
@_transparent
9851020
public mutating func formRemainder(dividingBy other: ${Self}) {
@@ -1454,10 +1489,13 @@ extension ${Self} {
14541489
return ${Self}(_bits: Builtin.int_fabs_FPIEEE${bits}(_value))
14551490
}
14561491

1457-
/// Creates the closest representable value to the given integer.
1458-
///
1459-
/// - Parameter value: The integer to represent as a floating-point value.
14601492
// FIXME(integers): implement properly
1493+
/// Creates a value that exactly represents the given integer.
1494+
///
1495+
/// If the given integer is outside the representable range of this type or
1496+
/// can't be represented exactly, the result is `nil`.
1497+
///
1498+
/// - Parameter source: The integer to represent as a floating-point value.
14611499
@_inlineable // FIXME(sil-serialize-all)
14621500
public init?<T : BinaryInteger>(exactly source: T) {
14631501
fatalError()

stdlib/public/core/Hashable.swift

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,32 @@
2828
/// equal hash values are not necessarily equal to each other.
2929
///
3030
/// - Important: Hash values are not guaranteed to be equal across different
31-
/// executions of your program. Do not save hash values to use in a
32-
/// future execution.
31+
/// executions of your program. Do not save hash values to use in a future
32+
/// execution.
3333
///
3434
/// Conforming to the Hashable Protocol
3535
/// ===================================
3636
///
3737
/// To use your own custom type in a set or as the key type of a dictionary,
38-
/// add `Hashable` conformance to your type by providing a `hashValue`
39-
/// property. The `Hashable` protocol inherits from the `Equatable` protocol,
40-
/// so you must also add an equal-to operator (`==`) function for your
41-
/// custom type.
38+
/// add `Hashable` conformance to your type. The `Hashable` protocol inherits
39+
/// from the `Equatable` protocol, so you must also satisfy that protocol's
40+
/// requirements.
41+
///
42+
/// A custom type's `Hashable` and `Equatable` requirements are automatically
43+
/// synthesized by the compiler when you declare `Hashable` conformance in the
44+
/// type's original declaration and your type meets these criteria:
45+
///
46+
/// - For a `struct`, all its stored properties must conform to `Hashable`.
47+
/// - For an `enum`, all its associated values must conform to `Hashable`. (An
48+
/// `enum` without associated values has `Hashable` conformance even without
49+
/// the declaration.)
50+
///
51+
/// To customize your type's `Hashable` conformance, to adopt `Hashable` in a
52+
/// type that doesn't meet the criteria listed above, or to extend an existing
53+
/// type to conform to `Hashable`, implement the `hashValue` property in your
54+
/// custom type. To ensure that your type meets the semantic requirements of
55+
/// the `Hashable` and `Equatable` protocols, it's a good idea to also
56+
/// customize your type's `Equatable` conformance to match.
4257
///
4358
/// As an example, consider a `GridPoint` type that describes a location in a
4459
/// grid of buttons. Here's the initial declaration of the `GridPoint` type:

stdlib/public/core/HashedCollections.swift.gyb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,8 @@ extension Set : Sequence {
566566
///
567567
/// - Parameter member: An element to look for in the set.
568568
/// - Returns: `true` if `member` exists in the set; otherwise, `false`.
569+
///
570+
/// - Complexity: O(1)
569571
@_inlineable // FIXME(sil-serialize-all)
570572
public func contains(_ member: Element) -> Bool {
571573
return _variantBuffer.maybeGet(member) != nil
@@ -650,6 +652,8 @@ extension Set : Collection {
650652
/// - Parameter member: An element to search for in the set.
651653
/// - Returns: The index of `member` if it exists in the set; otherwise,
652654
/// `nil`.
655+
///
656+
/// - Complexity: O(1)
653657
@_inlineable // FIXME(sil-serialize-all)
654658
public func index(of member: Element) -> Index? {
655659
return _variantBuffer.index(forKey: member)
@@ -1151,7 +1155,7 @@ extension Set : SetAlgebra {
11511155
/// instances of equivalent elements, only the first instance is kept.
11521156
///
11531157
/// var attendees: Set = ["Alicia", "Bethany", "Diana"]
1154-
/// let visitors = ["Diana", ""Marcia", "Nathaniel"]
1158+
/// let visitors = ["Diana", "Marcia", "Nathaniel"]
11551159
/// attendees.formUnion(visitors)
11561160
/// print(attendees)
11571161
/// // Prints "["Diana", "Nathaniel", "Bethany", "Alicia", "Marcia"]"
@@ -1754,9 +1758,10 @@ public struct Dictionary<Key : Hashable, Value> {
17541758
/// Creates a new dictionary from the key-value pairs in the given sequence.
17551759
///
17561760
/// You use this initializer to create a dictionary when you have a sequence
1757-
/// of key-value tuples with unique keys. If your sequence might have
1758-
/// duplicate keys, use the `Dictionary(_:uniquingKeysWith:)` initializer
1759-
/// instead.
1761+
/// of key-value tuples with unique keys. Passing a sequence with duplicate
1762+
/// keys to this initializer results in a runtime error. If your
1763+
/// sequence might have duplicate keys, use the
1764+
/// `Dictionary(_:uniquingKeysWith:)` initializer instead.
17601765
///
17611766
/// The following example creates a new dictionary using an array of strings
17621767
/// as the keys and the integers in a countable range as the values:

stdlib/public/core/Integers.swift.gyb

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1293,7 +1293,7 @@ extension Numeric {
12931293
/// // r == 82
12941294
/// // == 0b01010010
12951295
///
1296-
/// let s = Int16(truncatingIfNeeded: s) // extend 'r' to fill 16 bits
1296+
/// let s = Int16(truncatingIfNeeded: r) // extend 'r' to fill 16 bits
12971297
/// // s == 82
12981298
/// // == 0b00000000_01010010
12991299
///
@@ -1648,6 +1648,14 @@ ${operatorComment(x.nonMaskingOperator, False)}
16481648
// Strideable conformance
16491649
extension BinaryInteger {
16501650
// FIXME(ABI): using Int as the return type is wrong.
1651+
/// Returns the distance from this value to the given value, expressed as a
1652+
/// stride.
1653+
///
1654+
/// For two values `x` and `y`, and a distance `n = x.distance(to: y)`,
1655+
/// `x.advanced(by: n) == y`.
1656+
///
1657+
/// - Parameter other: The value to calculate the distance to.
1658+
/// - Returns: The distance from this value to `other`.
16511659
@_inlineable // FIXME(sil-serialize-all)
16521660
@inline(__always)
16531661
public func distance(to other: Self) -> Int {
@@ -1677,6 +1685,17 @@ extension BinaryInteger {
16771685
}
16781686

16791687
// FIXME(ABI): using Int as the parameter type is wrong.
1688+
/// Returns a value that is offset the specified distance from this value.
1689+
///
1690+
/// Use the `advanced(by:)` method in generic code to offset a value by a
1691+
/// specified distance. If you're working directly with numeric values, use
1692+
/// the addition operator (`+`) instead of this method.
1693+
///
1694+
/// For a value `x`, a distance `n`, and a value `y = x.advanced(by: n)`,
1695+
/// `x.distance(to: y) == n`.
1696+
///
1697+
/// - Parameter n: The distance to advance this value.
1698+
/// - Returns: A value that is offset from this value by `n`.
16801699
@_inlineable // FIXME(sil-serialize-all)
16811700
@inline(__always)
16821701
public func advanced(by n: Int) -> Self {
@@ -1696,12 +1715,31 @@ extension BinaryInteger {
16961715

16971716
extension Int {
16981717
// FIXME(ABI): using Int as the return type is wrong.
1718+
/// Returns the distance from this value to the given value, expressed as a
1719+
/// stride.
1720+
///
1721+
/// For two values `x` and `y`, and a distance `n = x.distance(to: y)`,
1722+
/// `x.advanced(by: n) == y`.
1723+
///
1724+
/// - Parameter other: The value to calculate the distance to.
1725+
/// - Returns: The distance from this value to `other`.
16991726
@_inlineable // FIXME(sil-serialize-all)
17001727
@_transparent
17011728
public func distance(to other: Int) -> Int {
17021729
return other - self
17031730
}
17041731

1732+
/// Returns a value that is offset the specified distance from this value.
1733+
///
1734+
/// Use the `advanced(by:)` method in generic code to offset a value by a
1735+
/// specified distance. If you're working directly with numeric values, use
1736+
/// the addition operator (`+`) instead of this method.
1737+
///
1738+
/// For a value `x`, a distance `n`, and a value `y = x.advanced(by: n)`,
1739+
/// `x.distance(to: y) == n`.
1740+
///
1741+
/// - Parameter n: The distance to advance this value.
1742+
/// - Returns: A value that is offset from this value by `n`.
17051743
// FIXME(ABI): using Int as the parameter type is wrong.
17061744
@_inlineable // FIXME(sil-serialize-all)
17071745
@_transparent
@@ -3207,6 +3245,7 @@ ${assignmentOperatorComment(x.operator, True)}
32073245
}
32083246

32093247
// FIXME should be RandomAccessCollection
3248+
/// A type that represents the words of this integer.
32103249
@_fixed_layout // FIXME(sil-serialize-all)
32113250
public struct Words : BidirectionalCollection {
32123251
public typealias Indices = CountableRange<Int>
@@ -3286,6 +3325,8 @@ ${assignmentOperatorComment(x.operator, True)}
32863325
Builtin.${truncOrExt}OrBitCast_Int${word_bits}_Int${bits}(bits._value))
32873326
}
32883327

3328+
/// A type that can represent the absolute value of any possible value of
3329+
/// this type.
32893330
public typealias Magnitude = ${U}${Self}
32903331

32913332
% if signed:

stdlib/public/core/LazyCollection.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ extension LazyCollection : Sequence {
8484
return _base.makeIterator()
8585
}
8686

87-
/// A value less than or equal to the number of elements in the collection.
87+
/// A value less than or equal to the number of elements in the sequence,
88+
/// calculated nondestructively.
8889
///
8990
/// - Complexity: O(1) if the collection conforms to
9091
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length

stdlib/public/core/ManagedBuffer.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,32 @@ public struct ManagedBufferPointer<Header, Element> : Equatable {
511511
/// myStorage.update(withValue: value)
512512
/// }
513513
///
514+
/// Use care when calling `isKnownUniquelyReferenced(_:)` from within a Boolean
515+
/// expression. In debug builds, an instance in the left-hand side of a `&&`
516+
/// or `||` expression may still be referenced when evaluating the right-hand
517+
/// side, inflating the instance's reference count. For example, this version
518+
/// of the `update(withValue)` method will re-copy `myStorage` on every call:
519+
///
520+
/// // Copies too frequently:
521+
/// mutating func badUpdate(withValue value: T) {
522+
/// if myStorage.shouldCopy || !isKnownUniquelyReferenced(&myStorage) {
523+
/// myStorage = self.copiedStorage()
524+
/// }
525+
/// myStorage.update(withValue: value)
526+
/// }
527+
///
528+
/// To avoid this behavior, swap the call `isKnownUniquelyReferenced(_:)` to
529+
/// the left-hand side or store the result of the first expression in a local
530+
/// constant:
531+
///
532+
/// mutating func goodUpdate(withValue value: T) {
533+
/// let shouldCopy = myStorage.shouldCopy
534+
/// if shouldCopy || !isKnownUniquelyReferenced(&myStorage) {
535+
/// myStorage = self.copiedStorage()
536+
/// }
537+
/// myStorage.update(withValue: value)
538+
/// }
539+
///
514540
/// `isKnownUniquelyReferenced(_:)` checks only for strong references to the
515541
/// given object---if `object` has additional weak or unowned references, the
516542
/// result may still be `true`. Because weak and unowned references cannot be

stdlib/public/core/Map.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ extension LazyMapCollection: Sequence {
126126
return Iterator(_base: _base.makeIterator(), _transform: _transform)
127127
}
128128

129-
/// A value less than or equal to the number of elements in the collection.
129+
/// A value less than or equal to the number of elements in the sequence,
130+
/// calculated nondestructively.
130131
///
131132
/// - Complexity: O(1) if the collection conforms to
132133
/// `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length

stdlib/public/core/Mirrors.swift.gyb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ extension ${Type[0]} : CustomReflectable {
4646
}
4747

4848
extension ${Type[0]} : CustomPlaygroundQuickLookable {
49+
/// A custom playground Quick Look for the `${Type[0]}` instance.
4950
@_inlineable // FIXME(sil-serialize-all)
5051
public var customPlaygroundQuickLook: PlaygroundQuickLook {
5152
return ${Type[1]}(${Type[2]})

0 commit comments

Comments
 (0)