[swift-evolution] Proposal: Add Initializers For Converting UnsafePointers to Int and Unit

Michael Buckley michael at buckleyisms.com
Thu Dec 10 23:04:48 CST 2015


Thanks Dimitri, Brent, and Joe for the feedback. Your additional comments
on the motivation were very helpful, Dimitri. If I'm not mistaken, there
has been no negative feedback expressed towards the proposal, nor have
there been any other alternatives proposed. I believe the next step in the
Swift evolution process is to draft a proposal in the swift-evolution
format and circulate it on this mailing list for refinement. So, without
further ado,

Introduction

Just as users can create Unsafe[Mutable]Pointers from Ints and UInts, they
should be able to create Ints and UInts from Unsafe[Mutable]Pointers. This
will allow users to call C functions with intptr_t and uintptr_t
parameters, and will allow users to perform more advanced pointer
arithmetic than is allowed by UnsafePointers.

Motivation

Swift currently lacks the ability to perform many complex operations on
pointers, such as checking pointer alignment, tagging pointers, or XORing
pointers (for working with XOR linked lists, for example). As a systems
programming language, Swift ought to be able to solve these problems
natively and concisely.

Additionally, since some C functions take intptr_t and uintptr_t
parameters, Swift currently has no ability to call these functions
directly. Users must wrap calls to these functions in C code.

Proposed solution

Initializers will be added to Int and UInt to convert from UnsafePointer
and UnsafeMutablePointer.

Currently, the only workaround which can solve these problems is to write
any code that requires pointer arithmetic in C. Writing this code in Swift
will be no safer than it is in C, as this is a fundamentally unsafe
operation. However, it will be cleaner in that users will not be forced to
write C code.

Detailed design

The initializers will be implemented using the built-in ptrtoint_Word
function.

extension UInt {
  init<T>(_ bitPattern: UnsafePointer<T>) {
    self = UInt(Builtin.ptrtoint_Word(bitPattern._rawValue))
  }

  init<T>(_ bitPattern: UnsafeMutablePointer<T>) {
    self = UInt(Builtin.ptrtoint_Word(bitPattern._rawValue))
  }
}

extension Int {
  init<T>(_ bitPattern: UnsafePointer<T>) {
    self = Int(Builtin.ptrtoint_Word(bitPattern._rawValue))
  }

  init<T>(_ bitPattern: UnsafeMutablePointer<T>) {
    self = Int(Builtin.ptrtoint_Word(bitPattern._rawValue))
  }
}

As an example, these initializers will allow the user to get the next
address of an XOR linked list in Swift.

struct XORLinkedList<T> {
  let address: UnsafePointer<T>

  ...

  func successor(_ predecessor: XORLinkedList<T>) -> XORLinkedList<T> {
    return XorLinkedList(UnsafePointer<T>(UInt(address) ^
UInt(predecessor.address)))
  }
}

Impact on existing code

There is no impact on existing code.

Alternatives considered

Three alternatives were considered.

The first alternative was to add an intValue function to
Unsafe[Mutable]Pointer. This alternative was rejected because it is
preferred that type conversions be implemented as initializers where
possible.

The next alternative was to add functions to Unsafe[Mutable]Pointer which
covered the identified pointer arithmetic cases. This alternative was
rejected because it either would have required us to imagine every use-case
of pointer arithmetic and write functions for them, which is an impossible
task, or it would have required adding a full suite of arithmetic and
bitwise operators to Unsafe[Mutable]Pointer. Because some of these
operations are defined only on signed integers, and others on unsigned, it
would have required splitting Unsafe[Mutable]Pointer into signed and
unsigned variants, which would have complicated things for users who did
not need to do pointer arithmetic. Additionally, the implementations of
these operations would have probably converted the pointers to integers,
perform a single operation, and then convert them back. When chaining
operations, this would create a lot of unnecessary conversions.

The last alternative was to forgo these initializers and force users to
write all their complicated pointer code in C. This alternative was
rejected because it makes Swift less useful as a systems programming
language.

On Wed, Dec 9, 2015 at 1:55 PM, Dmitri Gribenko via swift-evolution <
swift-evolution at swift.org> wrote:

> On Wed, Dec 9, 2015 at 1:15 PM, Brent Royal-Gordon via swift-evolution
> <swift-evolution at swift.org> wrote:
> >> On the off chance you're trying to do loads from unaligned
> UnsafePointers, that's undefined in the current interface. You'll need to
> memcpy to well-aligned memory first.
> >
> > The buffer I’m accessing is UInt8, which I believe is always aligned,
> right?
> >
> > C:
> >
> >         typedef struct MIDIMetaEvent
> >         {
> >                 UInt8           metaEventType;
> >                 UInt8           unused1;
> >                 UInt8           unused2;
> >                 UInt8           unused3;
> >                 UInt32          dataLength;
> >                 UInt8           data[1];
> >         } MIDIMetaEvent;
> >
> > Swift:
> >
> >         public struct MIDIMetaEvent {
> >
> >             public var metaEventType: UInt8
> >             public var unused1: UInt8
> >             public var unused2: UInt8
> >             public var unused3: UInt8
> >             public var dataLength: UInt32
> >             public var data: (UInt8)
> >             public init()
> >             public init(metaEventType: UInt8, unused1: UInt8, unused2:
> UInt8, unused3: UInt8, dataLength: UInt32, data: (UInt8))
> >         }
>
> FWIW, this problem looks very much like one for which we did the
> CoreAudio overlay: stdlib/public/SDK/CoreAudio/CoreAudio.swift
>
> Dmitri
>
> --
> main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
> (j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151210/cd7dc78a/attachment.html>


More information about the swift-evolution mailing list