Skip to content

[stdlib] Revise unsafe pointers documentation #6275

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 5 commits into from
Dec 22, 2016
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
22 changes: 16 additions & 6 deletions stdlib/public/core/BridgeObjectiveC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -469,15 +469,20 @@ public struct AutoreleasingUnsafeMutablePointer<Pointee /* TODO : class */>
}

extension UnsafeMutableRawPointer {
/// Convert from `AutoreleasingUnsafeMutablePointer`.
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
/// instance.
///
/// - Parameter other: The pointer to convert.
@_transparent
public init<T>(_ other: AutoreleasingUnsafeMutablePointer<T>) {
_rawValue = other._rawValue
}

/// Convert other `AutoreleasingUnsafeMutablePointer`.
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
/// instance.
///
/// Returns nil if `other` is nil.
/// - Parameter other: The pointer to convert. If `other` is `nil`, the
/// result is `nil`.
@_transparent
public init?<T>(_ other: AutoreleasingUnsafeMutablePointer<T>?) {
guard let unwrapped = other else { return nil }
Expand All @@ -486,15 +491,20 @@ extension UnsafeMutableRawPointer {
}

extension UnsafeRawPointer {
/// Convert other `AutoreleasingUnsafeMutablePointer`.
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
/// instance.
///
/// - Parameter other: The pointer to convert.
@_transparent
public init<T>(_ other: AutoreleasingUnsafeMutablePointer<T>) {
_rawValue = other._rawValue
}

/// Convert other `AutoreleasingUnsafeMutablePointer`.
/// Creates a new raw pointer from an `AutoreleasingUnsafeMutablePointer`
/// instance.
///
/// Returns nil if `other` is nil.
/// - Parameter other: The pointer to convert. If `other` is `nil`, the
/// result is `nil`.
@_transparent
public init?<T>(_ other: AutoreleasingUnsafeMutablePointer<T>?) {
guard let unwrapped = other else { return nil }
Expand Down
32 changes: 27 additions & 5 deletions stdlib/public/core/Builtin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,36 @@ func _canBeClass<T>(_: T.Type) -> Int8 {
return Int8(Builtin.canBeClass(T.self))
}

/// Returns the bits of `x`, interpreted as having type `U`.
/// Returns the bits of the given instance, interpreted as having the specified
/// type.
///
/// - Warning: Breaks the guarantees of Swift's type system; use
/// with extreme care. There's almost always a better way to do
/// anything.
/// Only use this function to convert the instance passed as `x` to a
/// layout-compatible type when the conversion is not possible through other
/// means. Common conversions that are supported by the standard library
/// include the following:
///
/// - To convert an integer value from one type to another, use an initializer
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO, this is a bit of a jump. I think you need a connective that communicates that you are provided a list of "other means" for common operations when people instinctively reach for unsafeBitCast.

There is no reason not to be more explicit... thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good note, thanks!

/// or the `numericCast(_:)` function.
/// - To perform a bitwise conversion of an integer value to a different type,
/// use an `init(bitPattern:)` or `init(truncatingBitPattern:)` initializer.
/// - To convert between a pointer and an integer value with that bit pattern,
/// or vice versa, use the `init(bitPattern:)` initializer for the
/// destination type.
/// - To perform a reference cast, use the casting operators (`as`, `as!`, or
/// `as?`) or the `unsafeDowncast(_:to:)` function. Do not use
/// `unsafeBitCast(_:to:)` with class or pointer types; doing so may
/// introduce undefined behavior.
///
/// - Warning: Calling this function breaks the guarantees of Swift's type
/// system; use with extreme care.
///
/// - Parameters:
/// - x: The instance to cast to `type`.
/// - type: The type to cast `x` to. `type` and the type of `x` must have the
/// same size of memory representation and compatible memory layout.
/// - Returns: A new instance of type `U`, cast from `x`.
@_transparent
public func unsafeBitCast<T, U>(_ x: T, to: U.Type) -> U {
public func unsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
_precondition(MemoryLayout<T>.size == MemoryLayout<U>.size,
"can't unsafeBitCast between types of different sizes")
return Builtin.reinterpretCast(x)
Expand Down
75 changes: 44 additions & 31 deletions stdlib/public/core/ManagedBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -440,31 +440,39 @@ public func == <Header, Element>(

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

/// Returns a Boolean value indicating whether the given object is a
/// class instance known to have a single strong reference.
/// Returns a Boolean value indicating whether the given object is known to
/// have a single strong reference.
///
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing
/// the copy-on-write optimization for the deep storage of value types:
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing the
/// copy-on-write optimization for the deep storage of value types:
///
/// mutating func modifyMe(_ arg: X) {
/// if isKnownUniquelyReferenced(&myStorage) {
/// myStorage.modifyInPlace(arg)
/// } else {
/// myStorage = self.createModified(myStorage, arg)
/// mutating func update(withValue value: T) {
/// if !isKnownUniquelyReferenced(&myStorage) {
/// myStorage = self.copiedStorage()
/// }
/// myStorage.update(withValue: value)
/// }
///
/// Weak references do not affect the result of this function.
/// `isKnownUniquelyReferenced(_:)` checks only for strong references to the
/// given object---if `object` has additional weak or unowned references, the
/// result may still be `true`. Because weak and unowned references cannot be
/// the only reference to an object, passing a weak or unowned reference as
/// `object` always results in `false`.
///
/// This function is safe to use for mutating functions in multithreaded code
/// because a false positive implies that there is already a user-level data
/// race on the value being mutated.
/// If the instance passed as `object` is being accessed by multiple threads
/// simultaneously, this function may still return `true`. Therefore, you must
/// only call this function from mutating methods with appropriate thread
/// synchronization. That will ensure that `isKnownUniquelyReferenced(_:)`
/// only returns `true` when there is really one accessor, or when there is a
/// race condition, which is already undefined behavior.
///
/// - Parameter object: An instance of a class. This function does *not* modify
/// `object`; the use of `inout` is an implementation artifact.
/// - Returns: `true` if `object` is a known to have a
/// single strong reference; otherwise, `false`.
/// - Returns: `true` if `object` is known to have a single strong reference;
/// otherwise, `false`.
public func isKnownUniquelyReferenced<T : AnyObject>(_ object: inout T) -> Bool
{
return _isUnique(&object)
Expand All @@ -474,31 +482,36 @@ internal func _isKnownUniquelyReferencedOrPinned<T : AnyObject>(_ object: inout
return _isUniqueOrPinned(&object)
}

/// Returns a Boolean value indicating whether the given object is a
/// class instance known to have a single strong reference.
/// Returns a Boolean value indicating whether the given object is known to
/// have a single strong reference.
///
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing
/// the copy-on-write optimization for the deep storage of value types:
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing the
/// copy-on-write optimization for the deep storage of value types:
///
/// mutating func modifyMe(_ arg: X) {
/// if isKnownUniquelyReferenced(&myStorage) {
/// myStorage.modifyInPlace(arg)
/// } else {
/// myStorage = self.createModified(myStorage, arg)
/// mutating func update(withValue value: T) {
/// if !isKnownUniquelyReferenced(&myStorage) {
/// myStorage = self.copiedStorage()
/// }
/// myStorage.update(withValue: value)
/// }
///
/// Weak references do not affect the result of this function.
/// `isKnownUniquelyReferenced(_:)` checks only for strong references to the
/// given object---if `object` has additional weak or unowned references, the
/// result may still be `true`. Because weak and unowned references cannot be
/// the only reference to an object, passing a weak or unowned reference as
/// `object` always results in `false`.
///
/// This function is safe to use for mutating functions in multithreaded code
/// because a false positive implies that there is already a user-level data
/// race on the value being mutated.
/// If the instance passed as `object` is being accessed by multiple threads
/// simultaneously, this function may still return `true`. Therefore, you must
/// only call this function from mutating methods with appropriate thread
/// synchronization. That will ensure that `isKnownUniquelyReferenced(_:)`
/// only returns `true` when there is really one accessor, or when there is a
/// race condition, which is already undefined behavior.
///
/// - Parameter object: An instance of a class. This function does *not* modify
/// `object`; the use of `inout` is an implementation artifact.
/// - Returns: `true` if `object` is a known to have a
/// single strong reference; otherwise, `false`. If `object` is `nil`, the
/// return value is `false`.
/// - Returns: `true` if `object` is known to have a single strong reference;
/// otherwise, `false`. If `object` is `nil`, the return value is `false`.
public func isKnownUniquelyReferenced<T : AnyObject>(
_ object: inout T?
) -> Bool {
Expand Down
132 changes: 114 additions & 18 deletions stdlib/public/core/MemoryLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,156 @@
//===----------------------------------------------------------------------===//

/// The memory layout of a type, describing its size, stride, and alignment.
///
/// You can use `MemoryLayout` as a source of information about a type when
/// allocating or binding memory using unsafe pointers. The following example
/// declares a `Point` type with `x` and `y` coordinates and a Boolean
/// `isFilled` property.
///
/// struct Point {
/// let x: Double
/// let y: Double
/// let isFilled: Bool
/// }
///
/// The size, stride, and alignment of the `Point` type are accessible as
/// static properties of `MemoryLayout<Point>`.
///
/// // MemoryLayout<Point>.size == 17
/// // MemoryLayout<Point>.stride == 24
/// // MemoryLayout<Point>.alignment == 8
///
/// Always use a multiple of a type's `stride` instead of its `size` when
/// allocating memory or accounting for the distance between instances in
/// memory. This example allocates untyped, uninitialized memory with space
/// for four instances of `Point`.
///
/// let count = 4
/// let pointPointer = UnsafeMutableRawPointer.allocate(
/// bytes: count * MemoryLayout<Point>.stride,
/// alignedTo: MemoryLayout<Point>.alignment)
public enum MemoryLayout<T> {
/// The contiguous memory footprint of `T`.
/// The contiguous memory footprint of `T`, in bytes.
///
/// Does not include any dynamically-allocated or "remote" storage. In
/// particular, `MemoryLayout<T>.size`, when `T` is a class type, is the same
/// regardless of how many stored properties `T` has.
/// A type's size does not include any dynamically allocated or out of line
/// storage. In particular, `MemoryLayout<T>.size`, when `T` is a class
/// type, is the same regardless of how many stored properties `T` has.
///
/// When allocating memory for multiple instances of `T` using an unsafe
/// pointer, use a multiple of the type's stride instead of its size.
///
/// - SeeAlso: `stride`
@_transparent
public static var size: Int {
return Int(Builtin.sizeof(T.self))
}

/// The number of bytes from the start of one instance of `T` to the start of
/// the next in an `Array<T>`.
/// the next when stored in contiguous memory or in an `Array<T>`.
///
/// This is the same as the number of bytes moved when an `UnsafePointer<T>`
/// is incremented. `T` may have a lower minimal alignment that trades runtime
/// performance for space efficiency. The result is always positive.
/// instance is incremented. `T` may have a lower minimal alignment that
/// trades runtime performance for space efficiency. This value is always
/// positive.
@_transparent
public static var stride: Int {
return Int(Builtin.strideof(T.self))
}

/// The default memory alignment of `T`.
/// The default memory alignment of `T`, in bytes.
///
/// Use the `alignment` property for a type when allocating memory using an
/// unsafe pointer. This value is always positive.
@_transparent
public static var alignment: Int {
return Int(Builtin.alignof(T.self))
}
}

extension MemoryLayout {
/// Returns the contiguous memory footprint of `T`.
/// Returns the contiguous memory footprint of the given instance.
///
/// The result does not include any dynamically allocated or out of line
/// storage. In particular, pointers and class instances all have the same
/// contiguous memory footprint, regardless of the size of the referenced
/// data.
///
/// When you have a type instead of an instance, use the
/// `MemoryLayout<T>.size` static property instead.
///
/// let x: Int = 100
///
/// Does not include any dynamically-allocated or "remote" storage. In
/// particular, `MemoryLayout.size(ofValue: x)`, when `x` is a class instance,
/// is the same regardless of how many stored properties `T` has.
/// // Finding the size of a value's type
/// let s = MemoryLayout.size(ofValue: x)
/// // s == 8
///
/// // Finding the size of a type directly
/// let t = MemoryLayout<Int>.size
/// // t == 8
///
/// - Parameter value: A value representative of the type to describe.
/// - Returns: The size, in bytes, of the given value's type.
///
/// - SeeAlso: `MemoryLayout.size`
@_transparent
public static func size(ofValue _: T) -> Int {
public static func size(ofValue value: T) -> Int {
return MemoryLayout.size
}

/// Returns the number of bytes from the start of one instance of `T` to the
/// start of the next in an `Array<T>`.
/// start of the next when stored in contiguous memory or in an `Array<T>`.
///
/// This is the same as the number of bytes moved when an `UnsafePointer<T>`
/// is incremented. `T` may have a lower minimal alignment that trades runtime
/// performance for space efficiency. The result is always positive.
/// instance is incremented. `T` may have a lower minimal alignment that
/// trades runtime performance for space efficiency. The result is always
/// positive.
///
/// When you have a type instead of an instance, use the
/// `MemoryLayout<T>.stride` static property instead.
///
/// let x: Int = 100
///
/// // Finding the stride of a value's type
/// let s = MemoryLayout.stride(ofValue: x)
/// // s == 8
///
/// // Finding the stride of a type directly
/// let t = MemoryLayout<Int>.stride
/// // t == 8
///
/// - Parameter value: A value representative of the type to describe.
/// - Returns: The stride, in bytes, of the given value's type.
///
/// - SeeAlso: `MemoryLayout.stride`
@_transparent
public static func stride(ofValue _: T) -> Int {
public static func stride(ofValue value: T) -> Int {
return MemoryLayout.stride
}

/// Returns the default memory alignment of `T`.
///
/// Use a type's alignment when allocating memory using an unsafe pointer.
///
/// When you have a type instead of an instance, use the
/// `MemoryLayout<T>.stride` static property instead.
///
/// let x: Int = 100
///
/// // Finding the alignment of a value's type
/// let s = MemoryLayout.alignment(ofValue: x)
/// // s == 8
///
/// // Finding the alignment of a type directly
/// let t = MemoryLayout<Int>.alignment
/// // t == 8
///
/// - Parameter value: A value representative of the type to describe.
/// - Returns: The default memory alignment, in bytes, of the given value's
/// type. This value is always positive.
///
/// - SeeAlso: `MemoryLayout.alignment`
@_transparent
public static func alignment(ofValue _: T) -> Int {
public static func alignment(ofValue value: T) -> Int {
return MemoryLayout.alignment
}
}
Loading