Skip to content

Commit 0a0c77e

Browse files
authored
Merge pull request #6275 from natecook1000/nc-revise-pointers
[stdlib] Revise unsafe pointers documentation
2 parents 7915037 + 4edccfe commit 0a0c77e

8 files changed

+1770
-535
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: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,36 @@ 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. Common conversions that are supported by the standard library
88+
/// include the following:
8789
///
90+
/// - To convert an integer value from one type to another, use an initializer
91+
/// or the `numericCast(_:)` function.
92+
/// - To perform a bitwise conversion of an integer value to a different type,
93+
/// use an `init(bitPattern:)` or `init(truncatingBitPattern:)` initializer.
94+
/// - To convert between a pointer and an integer value with that bit pattern,
95+
/// or vice versa, use the `init(bitPattern:)` initializer for the
96+
/// destination type.
97+
/// - To perform a reference cast, use the casting operators (`as`, `as!`, or
98+
/// `as?`) or the `unsafeDowncast(_:to:)` function. Do not use
99+
/// `unsafeBitCast(_:to:)` with class or pointer types; doing so may
100+
/// introduce undefined behavior.
101+
///
102+
/// - Warning: Calling this function breaks the guarantees of Swift's type
103+
/// system; use with extreme care.
104+
///
105+
/// - Parameters:
106+
/// - x: The instance to cast to `type`.
107+
/// - type: The type to cast `x` to. `type` and the type of `x` must have the
108+
/// same size of memory representation and compatible memory layout.
109+
/// - Returns: A new instance of type `U`, cast from `x`.
88110
@_transparent
89-
public func unsafeBitCast<T, U>(_ x: T, to: U.Type) -> U {
111+
public func unsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
90112
_precondition(MemoryLayout<T>.size == MemoryLayout<U>.size,
91113
"can't unsafeBitCast between types of different sizes")
92114
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: 114 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,60 +11,156 @@
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 out of line
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 instead of its size.
51+
///
52+
/// - SeeAlso: `stride`
2053
@_transparent
2154
public static var size: Int {
2255
return Int(Builtin.sizeof(T.self))
2356
}
2457

2558
/// The number of bytes from the start of one instance of `T` to the start of
26-
/// the next in an `Array<T>`.
59+
/// the next when stored in contiguous memory or in an `Array<T>`.
2760
///
2861
/// 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.
62+
/// instance is incremented. `T` may have a lower minimal alignment that
63+
/// trades runtime performance for space efficiency. This value is always
64+
/// positive.
3165
@_transparent
3266
public static var stride: Int {
3367
return Int(Builtin.strideof(T.self))
3468
}
3569

36-
/// The default memory alignment of `T`.
70+
/// The default memory alignment of `T`, in bytes.
71+
///
72+
/// Use the `alignment` property for a type when allocating memory using an
73+
/// unsafe pointer. This value is always positive.
3774
@_transparent
3875
public static var alignment: Int {
3976
return Int(Builtin.alignof(T.self))
4077
}
4178
}
4279

4380
extension MemoryLayout {
44-
/// Returns the contiguous memory footprint of `T`.
81+
/// Returns the contiguous memory footprint of the given instance.
82+
///
83+
/// The result does not include any dynamically allocated or out of line
84+
/// storage. In particular, pointers and class instances all have the same
85+
/// contiguous memory footprint, regardless of the size of the referenced
86+
/// data.
87+
///
88+
/// When you have a type instead of an instance, use the
89+
/// `MemoryLayout<T>.size` static property instead.
90+
///
91+
/// let x: Int = 100
4592
///
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.
93+
/// // Finding the size of a value's type
94+
/// let s = MemoryLayout.size(ofValue: x)
95+
/// // s == 8
96+
///
97+
/// // Finding the size of a type directly
98+
/// let t = MemoryLayout<Int>.size
99+
/// // t == 8
100+
///
101+
/// - Parameter value: A value representative of the type to describe.
102+
/// - Returns: The size, in bytes, of the given value's type.
103+
///
104+
/// - SeeAlso: `MemoryLayout.size`
49105
@_transparent
50-
public static func size(ofValue _: T) -> Int {
106+
public static func size(ofValue value: T) -> Int {
51107
return MemoryLayout.size
52108
}
53109

54110
/// Returns the number of bytes from the start of one instance of `T` to the
55-
/// start of the next in an `Array<T>`.
111+
/// start of the next when stored in contiguous memory or in an `Array<T>`.
56112
///
57113
/// 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.
114+
/// instance is incremented. `T` may have a lower minimal alignment that
115+
/// trades runtime performance for space efficiency. The result is always
116+
/// positive.
117+
///
118+
/// When you have a type instead of an instance, use the
119+
/// `MemoryLayout<T>.stride` static property instead.
120+
///
121+
/// let x: Int = 100
122+
///
123+
/// // Finding the stride of a value's type
124+
/// let s = MemoryLayout.stride(ofValue: x)
125+
/// // s == 8
126+
///
127+
/// // Finding the stride of a type directly
128+
/// let t = MemoryLayout<Int>.stride
129+
/// // t == 8
130+
///
131+
/// - Parameter value: A value representative of the type to describe.
132+
/// - Returns: The stride, in bytes, of the given value's type.
133+
///
134+
/// - SeeAlso: `MemoryLayout.stride`
60135
@_transparent
61-
public static func stride(ofValue _: T) -> Int {
136+
public static func stride(ofValue value: T) -> Int {
62137
return MemoryLayout.stride
63138
}
64139

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

0 commit comments

Comments
 (0)