Skip to content

Commit 7494e20

Browse files
committed
[stdlib] Revise unsafe pointers documentation
This revises and expands upon documentation for the standard library's unsafe pointer types. This includes typed and raw pointers and buffers, the MemoryLayout type, and some other top-level functions.
1 parent 907ff36 commit 7494e20

8 files changed

+1637
-527
lines changed

stdlib/public/core/BridgeObjectiveC.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -469,15 +469,20 @@ public struct AutoreleasingUnsafeMutablePointer<Pointee /* TODO : class */>
469469
}
470470

471471
extension UnsafeMutableRawPointer {
472-
/// Convert from `AutoreleasingUnsafeMutablePointer`.
472+
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
473+
/// instance.
474+
///
475+
/// - Parameter other: The pointer to convert.
473476
@_transparent
474477
public init<T>(_ other: AutoreleasingUnsafeMutablePointer<T>) {
475478
_rawValue = other._rawValue
476479
}
477480

478-
/// Convert other `AutoreleasingUnsafeMutablePointer`.
481+
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
482+
/// instance.
479483
///
480-
/// Returns nil if `other` is nil.
484+
/// - Parameter other: The pointer to convert. If `other` is `nil`, the
485+
/// result is `nil`.
481486
@_transparent
482487
public init?<T>(_ other: AutoreleasingUnsafeMutablePointer<T>?) {
483488
guard let unwrapped = other else { return nil }
@@ -486,15 +491,20 @@ extension UnsafeMutableRawPointer {
486491
}
487492

488493
extension UnsafeRawPointer {
489-
/// Convert other `AutoreleasingUnsafeMutablePointer`.
494+
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
495+
/// instance.
496+
///
497+
/// - Parameter other: The pointer to convert.
490498
@_transparent
491499
public init<T>(_ other: AutoreleasingUnsafeMutablePointer<T>) {
492500
_rawValue = other._rawValue
493501
}
494502

495-
/// Convert other `AutoreleasingUnsafeMutablePointer`.
503+
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
504+
/// instance.
496505
///
497-
/// Returns nil if `other` is nil.
506+
/// - Parameter other: The pointer to convert. If `other` is `nil`, the
507+
/// result is `nil`.
498508
@_transparent
499509
public init?<T>(_ other: AutoreleasingUnsafeMutablePointer<T>?) {
500510
guard let unwrapped = other else { return nil }

stdlib/public/core/Builtin.swift

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,35 @@ func _canBeClass<T>(_: T.Type) -> Int8 {
7979
return Int8(Builtin.canBeClass(T.self))
8080
}
8181

82-
/// Returns the bits of `x`, interpreted as having type `U`.
82+
/// Returns the bits of the given instance, interpreted as having the specified
83+
/// type.
8384
///
84-
/// - Warning: Breaks the guarantees of Swift's type system; use
85-
/// with extreme care. There's almost always a better way to do
86-
/// anything.
85+
/// Only use this function to convert the instance passed as `x` to a
86+
/// layout-compatible type when the conversion is not possible through other
87+
/// means.
8788
///
89+
/// - To convert an integer value from one type to another, use an initializer
90+
/// or the `numericCast(_:)` function.
91+
/// - To perform a bitwise conversion of an integer value to a different type,
92+
/// use an `init(bitPattern:)` or `init(truncatingBitPattern:)` initializer.
93+
/// - To convert between a pointer and an integer value with that bit pattern,
94+
/// or vice versa, use the `init(bitPattern:)` initializer for the
95+
/// destination type.
96+
/// - To perform a reference cast, use the casting operators (`as`, `as!`, or
97+
/// `as?`) or the `unsafeDowncast(_:to:)` function. Do not use
98+
/// `unsafeBitCast(_:to:)` with class or pointer types; doing so may
99+
/// introduce undefined behavior.
100+
///
101+
/// - Warning: Calling this function breaks the guarantees of Swift's type
102+
/// system; use with extreme care.
103+
///
104+
/// - Parameters:
105+
/// - x: The instance to cast to `type`.
106+
/// - type: The type to cast `x` to. `type` and the type of `x` must have the
107+
/// same size of memory representation and compatible memory layout.
108+
/// - Returns: A new instance of type `U`, cast from `x`.
88109
@_transparent
89-
public func unsafeBitCast<T, U>(_ x: T, to: U.Type) -> U {
110+
public func unsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
90111
_precondition(MemoryLayout<T>.size == MemoryLayout<U>.size,
91112
"can't unsafeBitCast between types of different sizes")
92113
return Builtin.reinterpretCast(x)

stdlib/public/core/ManagedBuffer.swift

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -440,31 +440,39 @@ public func == <Header, Element>(
440440

441441
// FIXME: when our calling convention changes to pass self at +0,
442442
// inout should be dropped from the arguments to these functions.
443+
// FIXME(docs): isKnownUniquelyReferenced should check weak/unowned counts too,
444+
// but currently does not. rdar://problem/29341361
443445

444-
/// Returns a Boolean value indicating whether the given object is a
445-
/// class instance known to have a single strong reference.
446+
/// Returns a Boolean value indicating whether the given object is known to
447+
/// have a single strong reference.
446448
///
447-
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing
448-
/// the copy-on-write optimization for the deep storage of value types:
449+
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing the
450+
/// copy-on-write optimization for the deep storage of value types:
449451
///
450-
/// mutating func modifyMe(_ arg: X) {
451-
/// if isKnownUniquelyReferenced(&myStorage) {
452-
/// myStorage.modifyInPlace(arg)
453-
/// } else {
454-
/// myStorage = self.createModified(myStorage, arg)
452+
/// mutating func update(withValue value: T) {
453+
/// if !isKnownUniquelyReferenced(&myStorage) {
454+
/// myStorage = self.copiedStorage()
455455
/// }
456+
/// myStorage.update(withValue: value)
456457
/// }
457458
///
458-
/// Weak references do not affect the result of this function.
459+
/// `isKnownUniquelyReferenced(_:)` checks only for strong references to the
460+
/// given object---if `object` has additional weak or unowned references, the
461+
/// result may still be `true`. Because weak and unowned references cannot be
462+
/// the only reference to an object, passing a weak or unowned reference as
463+
/// `object` always results in `false`.
459464
///
460-
/// This function is safe to use for mutating functions in multithreaded code
461-
/// because a false positive implies that there is already a user-level data
462-
/// race on the value being mutated.
465+
/// If the instance passed as `object` is being accessed by multiple threads
466+
/// simultaneously, this function may still return `true`. Therefore, you must
467+
/// only call this function from mutating methods with appropriate thread
468+
/// synchronization. That will ensure that `isKnownUniquelyReferenced(_:)`
469+
/// only returns `true` when there is really one accessor, or when there is a
470+
/// race condition, which is already undefined behavior.
463471
///
464472
/// - Parameter object: An instance of a class. This function does *not* modify
465473
/// `object`; the use of `inout` is an implementation artifact.
466-
/// - Returns: `true` if `object` is a known to have a
467-
/// single strong reference; otherwise, `false`.
474+
/// - Returns: `true` if `object` is known to have a single strong reference;
475+
/// otherwise, `false`.
468476
public func isKnownUniquelyReferenced<T : AnyObject>(_ object: inout T) -> Bool
469477
{
470478
return _isUnique(&object)
@@ -474,31 +482,36 @@ internal func _isKnownUniquelyReferencedOrPinned<T : AnyObject>(_ object: inout
474482
return _isUniqueOrPinned(&object)
475483
}
476484

477-
/// Returns a Boolean value indicating whether the given object is a
478-
/// class instance known to have a single strong reference.
485+
/// Returns a Boolean value indicating whether the given object is known to
486+
/// have a single strong reference.
479487
///
480-
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing
481-
/// the copy-on-write optimization for the deep storage of value types:
488+
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing the
489+
/// copy-on-write optimization for the deep storage of value types:
482490
///
483-
/// mutating func modifyMe(_ arg: X) {
484-
/// if isKnownUniquelyReferenced(&myStorage) {
485-
/// myStorage.modifyInPlace(arg)
486-
/// } else {
487-
/// myStorage = self.createModified(myStorage, arg)
491+
/// mutating func update(withValue value: T) {
492+
/// if !isKnownUniquelyReferenced(&myStorage) {
493+
/// myStorage = self.copiedStorage()
488494
/// }
495+
/// myStorage.update(withValue: value)
489496
/// }
490497
///
491-
/// Weak references do not affect the result of this function.
498+
/// `isKnownUniquelyReferenced(_:)` checks only for strong references to the
499+
/// given object---if `object` has additional weak or unowned references, the
500+
/// result may still be `true`. Because weak and unowned references cannot be
501+
/// the only reference to an object, passing a weak or unowned reference as
502+
/// `object` always results in `false`.
492503
///
493-
/// This function is safe to use for mutating functions in multithreaded code
494-
/// because a false positive implies that there is already a user-level data
495-
/// race on the value being mutated.
504+
/// If the instance passed as `object` is being accessed by multiple threads
505+
/// simultaneously, this function may still return `true`. Therefore, you must
506+
/// only call this function from mutating methods with appropriate thread
507+
/// synchronization. That will ensure that `isKnownUniquelyReferenced(_:)`
508+
/// only returns `true` when there is really one accessor, or when there is a
509+
/// race condition, which is already undefined behavior.
496510
///
497511
/// - Parameter object: An instance of a class. This function does *not* modify
498512
/// `object`; the use of `inout` is an implementation artifact.
499-
/// - Returns: `true` if `object` is a known to have a
500-
/// single strong reference; otherwise, `false`. If `object` is `nil`, the
501-
/// return value is `false`.
513+
/// - Returns: `true` if `object` is known to have a single strong reference;
514+
/// otherwise, `false`. If `object` is `nil`, the return value is `false`.
502515
public func isKnownUniquelyReferenced<T : AnyObject>(
503516
_ object: inout T?
504517
) -> Bool {

stdlib/public/core/MemoryLayout.swift

Lines changed: 115 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,60 +11,157 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
/// The memory layout of a type, describing its size, stride, and alignment.
14+
///
15+
/// You can use `MemoryLayout` as a source of information about a type when
16+
/// allocating or binding memory using unsafe pointers. The following example
17+
/// declares a `Point` type with `x` and `y` coordinates and a Boolean
18+
/// `isFilled` property.
19+
///
20+
/// struct Point {
21+
/// let x: Double
22+
/// let y: Double
23+
/// let isFilled: Bool
24+
/// }
25+
///
26+
/// The size, stride, and alignment of the `Point` type are accessible as
27+
/// static properties of `MemoryLayout<Point>`.
28+
///
29+
/// // MemoryLayout<Point>.size == 17
30+
/// // MemoryLayout<Point>.stride == 24
31+
/// // MemoryLayout<Point>.alignment == 8
32+
///
33+
/// Always use a multiple of a type's `stride` instead of its `size` when
34+
/// allocating memory or accounting for the distance between instances in
35+
/// memory. This example allocates untyped, uninitialized memory with space
36+
/// for four instances of `Point`.
37+
///
38+
/// let count = 4
39+
/// let pointPointer = UnsafeMutableRawPointer.allocate(
40+
/// bytes: count * MemoryLayout<Point>.stride,
41+
/// alignedTo: MemoryLayout<Point>.alignment)
1442
public enum MemoryLayout<T> {
15-
/// The contiguous memory footprint of `T`.
43+
/// The contiguous memory footprint of `T`, in bytes.
1644
///
17-
/// Does not include any dynamically-allocated or "remote" storage. In
18-
/// particular, `MemoryLayout<T>.size`, when `T` is a class type, is the same
19-
/// regardless of how many stored properties `T` has.
45+
/// A type's size does not include any dynamically allocated or remote
46+
/// storage. In particular, `MemoryLayout<T>.size`, when `T` is a class
47+
/// type, is the same regardless of how many stored properties `T` has.
48+
///
49+
/// When allocating memory for multiple instances of `T` using an unsafe
50+
/// pointer, use a multiple of the type's `stride` property instead of its
51+
/// `size`.
52+
///
53+
/// - SeeAlso: `stride`
2054
@_transparent
2155
public static var size: Int {
2256
return Int(Builtin.sizeof(T.self))
2357
}
2458

2559
/// The number of bytes from the start of one instance of `T` to the start of
26-
/// the next in an `Array<T>`.
60+
/// the next when stored in contiguous memory or in an `Array<T>`.
2761
///
2862
/// This is the same as the number of bytes moved when an `UnsafePointer<T>`
29-
/// is incremented. `T` may have a lower minimal alignment that trades runtime
30-
/// performance for space efficiency. The result is always positive.
63+
/// instance is incremented. `T` may have a lower minimal alignment that
64+
/// trades runtime performance for space efficiency. This value is always
65+
/// positive.
3166
@_transparent
3267
public static var stride: Int {
3368
return Int(Builtin.strideof(T.self))
3469
}
3570

36-
/// The default memory alignment of `T`.
71+
/// The default memory alignment of `T`, in bytes.
72+
///
73+
/// Use the `alignment` property for a type when allocating memory using an
74+
/// unsafe pointer. This value is always positive.
3775
@_transparent
3876
public static var alignment: Int {
3977
return Int(Builtin.alignof(T.self))
4078
}
4179
}
4280

4381
extension MemoryLayout {
44-
/// Returns the contiguous memory footprint of `T`.
82+
/// Returns the contiguous memory footprint of the given instance.
83+
///
84+
/// The result does not include any dynamically allocated or remote
85+
/// storage. In particular, `MemoryLayout.size(ofValue: x)`, when `x` is an
86+
/// instance of a class `C`, is the same regardless of how many stored
87+
/// properties `C` has.
88+
///
89+
/// When you have a type instead of an instance, use the
90+
/// `MemoryLayout<T>.size` static property instead.
91+
///
92+
/// let x: Int = 100
4593
///
46-
/// Does not include any dynamically-allocated or "remote" storage. In
47-
/// particular, `MemoryLayout.size(ofValue: x)`, when `x` is a class instance,
48-
/// is the same regardless of how many stored properties `T` has.
94+
/// // Finding the size of a value's type
95+
/// let s = MemoryLayout.size(ofValue: x)
96+
/// // s == 8
97+
///
98+
/// // Finding the size of a type directly
99+
/// let t = MemoryLayout<Int>.size
100+
/// // t == 8
101+
///
102+
/// - Parameter value: A value representative of the type to describe.
103+
/// - Returns: The size, in bytes, of the given value's type.
104+
///
105+
/// - SeeAlso: `MemoryLayout.size`
49106
@_transparent
50-
public static func size(ofValue _: T) -> Int {
107+
public static func size(ofValue value: T) -> Int {
51108
return MemoryLayout.size
52109
}
53110

54111
/// Returns the number of bytes from the start of one instance of `T` to the
55-
/// start of the next in an `Array<T>`.
112+
/// start of the next when stored in contiguous memory or in an `Array<T>`.
56113
///
57114
/// This is the same as the number of bytes moved when an `UnsafePointer<T>`
58-
/// is incremented. `T` may have a lower minimal alignment that trades runtime
59-
/// performance for space efficiency. The result is always positive.
115+
/// instance is incremented. `T` may have a lower minimal alignment that
116+
/// trades runtime performance for space efficiency. The result is always
117+
/// positive.
118+
///
119+
/// When you have a type instead of an instance, use the
120+
/// `MemoryLayout<T>.stride` static property instead.
121+
///
122+
/// let x: Int = 100
123+
///
124+
/// // Finding the stride of a value's type
125+
/// let s = MemoryLayout.stride(ofValue: x)
126+
/// // s == 8
127+
///
128+
/// // Finding the stride of a type directly
129+
/// let t = MemoryLayout<Int>.stride
130+
/// // t == 8
131+
///
132+
/// - Parameter value: A value representative of the type to describe.
133+
/// - Returns: The stride, in bytes, of the given value's type.
134+
///
135+
/// - SeeAlso: `MemoryLayout.stride`
60136
@_transparent
61-
public static func stride(ofValue _: T) -> Int {
137+
public static func stride(ofValue value: T) -> Int {
62138
return MemoryLayout.stride
63139
}
64140

65141
/// Returns the default memory alignment of `T`.
142+
///
143+
/// Use a type's alignment when allocating memory using an unsafe pointer.
144+
///
145+
/// When you have a type instead of an instance, use the
146+
/// `MemoryLayout<T>.stride` static property instead.
147+
///
148+
/// let x: Int = 100
149+
///
150+
/// // Finding the alignment of a value's type
151+
/// let s = MemoryLayout.alignment(ofValue: x)
152+
/// // s == 8
153+
///
154+
/// // Finding the alignment of a type directly
155+
/// let t = MemoryLayout<Int>.alignment
156+
/// // t == 8
157+
///
158+
/// - Parameter value: A value representative of the type to describe.
159+
/// - Returns: The default memory alignment, in bytes, of the given value's
160+
/// type. This value is always positive.
161+
///
162+
/// - SeeAlso: `MemoryLayout.alignment`
66163
@_transparent
67-
public static func alignment(ofValue _: T) -> Int {
164+
public static func alignment(ofValue value: T) -> Int {
68165
return MemoryLayout.alignment
69166
}
70167
}

0 commit comments

Comments
 (0)