Skip to content

Instantly share code, notes, and snippets.

@atrick
Last active September 28, 2017 23:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atrick/c1ed7afb598e5cc943bdac7683914e3e to your computer and use it in GitHub Desktop.
Save atrick/c1ed7afb598e5cc943bdac7683914e3e to your computer and use it in GitHub Desktop.

SE-0184 Part 1: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

Here I've listed the changes from SE-0184 that have been reviewed by the core team and are no longer considered controversial. Let's call this SE-1084 Part 1. The diff below summarizes SE-1084 Part 1 vs. Swift 4. The core team requests have been incorporated, and are annotated as "Amended" comments. The amendments are minor and almost exclusively revise the original Swift 3 API rather than calling into question anything newly introduced by SE-0184. Consequently, there's no need for those to go back to swift-evolution. The remainder of SE-0184, part 2, will introduce changes to the slice API in conjunction with the buffer API, so does need to go back to swift-evolution as a new proposal.

Allocation

struct UnsafePointer<Pointee>
{
+++ func deallocate()

    func withMemoryRebound<T, Result>(to:T.Type, capacity:Int, _ body:(UnsafePointer<T>) -> Result) 
         -> Result
}

struct UnsafeMutablePointer<Pointee>
{
    static func allocate<Pointee>(capacity:Int) -> UnsafeMutablePointer<Pointee>

--- func deallocate(capacity:Int)
+++ func deallocate()

}

struct UnsafeRawPointer
{
--- func deallocate(bytes:Int, alignedTo:Int)
+++ func deallocate()
}

struct UnsafeMutableRawPointer
{
--- static func allocate(bytes:Int, alignedTo:Int) -> UnsafeMutableRawPointer
// Amended: Renamed `bytes` to `byteCount`.
// Amended: Renamed `alignedTo` to `alignment`.
// Amended: Removed default alignment.
+++ static func allocate(byteCount:Int, alignment:Int) -> UnsafeMutableRawPointer

--- func deallocate(bytes:Int, alignedTo:Int)
+++ func deallocate()
}

struct UnsafeBufferPointer<Element>
{
+++ func deallocate()
}

struct UnsafeRawBufferPointer
{
    func deallocate()
}

struct UnsafeMutableRawBufferPointer 
{
// Amended: Renamed `bytes` to `byteCount`.
// Amended: Renamed `alignedTo` to `alignment`.
// Amended: Removed default alignment.
--- static func allocate(count:Int) -> UnsafeMutableRawBufferPointer
+++ static func allocate(byteCount:Int, alignment:Int) -> UnsafeMutableRawBufferPointer
    func deallocate()
}

Buffer Conversion

struct UnsafeBufferPointer<Element>
{
+++ init(_:UnsafeMutableBufferPointer<Element>)
}

struct UnsafeMutableBufferPointer<Element> 
{
+++ init(mutating:UnsafeBufferPointer<Element>)
}

Buffer Memory State

struct UnsafePointer<Pointee>
{

  func withMemoryRebound<T, Result>(to:T.Type, capacity:Int, _ body:(UnsafePointer<T>) -> Result) 
         -> Result
}

struct UnsafeMutablePointer<Pointee>
{
--- func initialize(to:Pointee, count:Int = 1)
+++ func initialize(repeating:Pointee, count:Int) // No default count.

// Amended: Rename `initializePointee` to `initialize`.
+++ func initialize(to:Pointee)

    func initialize(from:UnsafePointer<Pointee>, count:Int)

    func moveInitialize(from:UnsafeMutablePointer<Pointee>, count:Int)

+++ func assign(repeating:Pointee, count:Int)

    func assign(from:UnsafePointer<Pointee>, count:Int)

    func moveAssign(from:UnsafeMutablePointer<Pointee>, count:Int)

    func deinitialize(count:Int)

    func withMemoryRebound<T, Result>(to:T.Type, capacity:Int, _ body:(UnsafeMutablePointer<T>) -> Result) 
         -> Result
}

struct UnsafeRawPointer
{
    func bindMemory<T>(to:T.Type, count:Int) -> UnsafeMutablePointer<T>
}

struct UnsafeMutableRawPointer
{
--- func initializeMemory<T>(as:T.Type, at:Int = 0, count:Int = 1, to:T) -> UnsafeMutablePointer<T>
+++ func initializeMemory<T>(as:T.Type, repeating:T, count:Int) -> UnsafeMutablePointer<T>

    func initializeMemory<T>(as:T.Type, from:UnsafePointer<T>, count:Int) -> UnsafeMutablePointer<T>
    func moveInitializeMemory<T>(as:T.Type, from:UnsafeMutablePointer<T>, count:Int) 
         -> UnsafeMutablePointer<T>

    func bindMemory<T>(to:T.Type, count:Int) -> UnsafeMutablePointer<T>

--- func copyBytes(from:UnsafeRawPointer, count:Int)
// Amended: Rename `bytes` to `byteCount`.
+++ func copyMemory(from:UnsafeRawPointer, byteCount:Int)
}

struct UnsafeBufferPointer<Element>
{
+++ func withMemoryRebound<T, Result>
+++ (to:T.Type, _ body:(UnsafeBufferPointer<T>) -> Result)
}

struct UnsafeMutableBufferPointer<Element> 
{
+++ func initialize(repeating: Element) -> UnsafeMutableBufferPointer<T>
+++ func assign(repeating: Element)

+++ func withMemoryRebound<T, Result>
+++ (to:T.Type, _ body:(UnsafeMutableBufferPointer<T>) -> Result)
}

struct UnsafeRawBufferPointer
{
    func deallocate()
    
+++ func bindMemory<T>(to:T.Type) -> UnsafeBufferPointer<T>
}

struct UnsafeMutableRawBufferPointer 
{
+++ func initializeMemory<T>(as:T.Type, repeating:T) -> UnsafeMutableBufferPointer<T>

+++ func bindMemory<T>(to:T.Type) -> UnsafeMutableBufferPointer<T>
}

Source compatibility

Everything is additive except the following. Can we deprecate all of the original functions in Swift 5, then drop those from the binary later in Swift 6?

  • add deallocate() to all pointer types, replacing any existing deallocation methods

The migrator needs to drop the existing capacity and alignedTo arguments.

  • in UnsafeMutableRawPointer.allocate(count:alignedTo:) rename count to byteCount and alignedTo to alignment

  • in UnsafeMutableRawBufferPointer.allocate(count:) rename count to byteCount and add an alignment parameter

This change is source breaking but can be trivially automigrated. The alignment: parameter can be filled in with MemoryLayout<UInt>.stride.

  • fix the arguments to initialize(repeating:Pointee, count:Int)

Note: initialize(to:Pointee) is backward compatible whenever the caller relied on a default count=1.

An annotation could otherwise rename to to repeating, but we don't want that to interfere with the default count case, so this might need to be a migrator rule.

  • fix the ordering of the arguments in initializeMemory<Element>(as:at:count:to:), rename to: to repeating:, and remove the at: argument

This change is source breaking but can be trivially automigrated. The to argument changes position and is relabeled as repeating.

The migrator could be taught to convert the at: argument into pointer arithmetic on self. However, I found no code on github that uses the at: argument, so it is low priority.

  • rename copyBytes(from:count:) to copyMemory(from:byteCount:)

This change is source breaking but can be trivially automigrated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment