changes to pointer data types in Xcode 8 beta 6


(Dave Reed) #1

I'm trying to convert the following code (from the Big Nerd Ranch's Freddy JSON parser) that works in Xcode 8 beta 5 and convert it to work with beta 6. Essentially it appears it needs to take a Data object and convert it to a UnsafeBufferPointer<UInt8> if I understand it correctly.

    /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`.
    ///
    /// If the data is mutable, it is copied before parsing. The data's lifetime
    /// is extended for the duration of parsing.
    init(utf8Data inData: Data) {
        let data = (inData as NSData).copy() as! Data
        let buffer = UnsafeBufferPointer(start: UnsafePointer<UInt8>((data as NSData).bytes), count: data.count)
        self.init(buffer: buffer, owner: data)
    }

And this case appears to be going from a String to UnsafeBufferPointer<Uint8>

    /// Creates a `JSONParser` from the code units represented by the `string`.
    ///
    /// The synthesized string is lifetime-extended for the duration of parsing.
    init(string: String) {
        let codePoints = string.nulTerminatedUTF8
        let buffer = codePoints.withUnsafeBufferPointer { nulTerminatedBuffer in
            // don't want to include the nul termination in the buffer - trim it off
            UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1)
        }
        self.init(buffer: buffer, owner: codePoints)
    }

}

I understand pointers from my C/C++/Objective-C days but I don't yet understand the various Swift pointer types. Any help is appreciated.

Note: I don't work for Big Nerd Ranch. I'm just trying to use the code and better understand the various Swift pointer types.

Thanks,
Dave Reed


(Zachary Waldowski) #2

Nerd here!

That part of the code ends up not needing to go through the
UnsafeRawPointer API, as it's processing UTF-8 bytes, see also:
<https://github.com/bignerdranch/Freddy/pull/191>.

That being said, good resources for reading about the new pointer system
are:
- [SE-0107]:
<https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md>
- [The Apple API reference], once it's updated:
<https://developer.apple.com/reference/swift>

You can also look up the documentation using the "Documentation and API
Reference" menu in Xcode 8 Beta 6, as it's currently updated.

Sincerely,
Zachary Waldowski
zachary@bignerdranch.com

···

On Mon, Aug 15, 2016, at 03:05 PM, Dave Reed via swift-users wrote:

I'm trying to convert the following code (from the Big Nerd Ranch's
Freddy JSON parser) that works in Xcode 8 beta 5 and convert it to work
with beta 6. Essentially it appears it needs to take a Data object and
convert it to a UnsafeBufferPointer<UInt8> if I understand it correctly.

    /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`.
    ///
    /// If the data is mutable, it is copied before parsing. The data's
    lifetime
    /// is extended for the duration of parsing.
    init(utf8Data inData: Data) {
        let data = (inData as NSData).copy() as! Data
        let buffer = UnsafeBufferPointer(start:
        UnsafePointer<UInt8>((data as NSData).bytes), count: data.count)
        self.init(buffer: buffer, owner: data)
    }

And this case appears to be going from a String to
UnsafeBufferPointer<Uint8>

    /// Creates a `JSONParser` from the code units represented by the
    `string`.
    ///
    /// The synthesized string is lifetime-extended for the duration of
    parsing.
    init(string: String) {
        let codePoints = string.nulTerminatedUTF8
        let buffer = codePoints.withUnsafeBufferPointer {
        nulTerminatedBuffer in
            // don't want to include the nul termination in the buffer -
            trim it off
            UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress,
            count: nulTerminatedBuffer.count - 1)
        }
        self.init(buffer: buffer, owner: codePoints)
    }

}

I understand pointers from my C/C++/Objective-C days but I don't yet
understand the various Swift pointer types. Any help is appreciated.

Note: I don't work for Big Nerd Ranch. I'm just trying to use the code
and better understand the various Swift pointer types.

Thanks,
Dave Reed

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Andrew Trick) #3

I'm too late to help, but just to follow up...

If you're wondering how to migrate pointer conversion like this to 3.0:

  UnsafePointer<UInt8>(data.bytes)

  UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress,
    count: nulTerminatedBuffer.count - 1)

then there's a quick explanation here <https://gist.github.com/atrick/0283ae0e284610fd21ad6ed3f454a585>.

The proposal that Zach posted has more background:
https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md

You can get something working easily enough with pointer bitcasts or binding memory, but converting UnsafePointers is not something you should be doing here.

If the JSON parser has its own copy of the data, then it should simply have its own array:

    private let input: [UInt8]
    //deleted private let owner: Any?

    init(utf8Data inData: Data) {
  input = [UInt8](inData)
    }

    init(string: String) {
  input = [UInt8](string.utf8)
    }

If the JSON parser wanted to operate on data that is owned by someone else, then we need something like the UnsafeBytes type proposed here:

https://github.com/atrick/swift-evolution/blob/unsafebytes/proposals/NNNN-UnsafeBytes.md#detailed-design

    private let input: UnsafeBytes
    private let owner: Any?

    init(utf8Data inData: Data) {
  // Data should directly provide a
        // withUnsafeBytes<T>(_ body: (UnsafeBytes) -> R)
  input = inData.withUnsafeBytes { (p: UnsafePointer<UInt8>) in
            UnsafeBytes(start: UnsafeRawPointer(p), count: inData.count) }
  owner = inData
    }

Although, in the case of String input you still need to create a copy:

    init(string: String) {
  let utf8Array = [UInt8](string.utf8)
  input = utf8Array.withUnsafeBytes { $0 }
  owner = utf8Array
    }

Note that passing a String as an argument of type UnsafePointer<UInt8> works, but should never be done when calling Swift code. The lifetime of that pointer doesn't outlive the call.

-Andy

···

On Aug 15, 2016, at 3:05 PM, Dave Reed via swift-users <swift-users@swift.org> wrote:

I'm trying to convert the following code (from the Big Nerd Ranch's Freddy JSON parser) that works in Xcode 8 beta 5 and convert it to work with beta 6. Essentially it appears it needs to take a Data object and convert it to a UnsafeBufferPointer<UInt8> if I understand it correctly.

   /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`.
   ///
   /// If the data is mutable, it is copied before parsing. The data's lifetime
   /// is extended for the duration of parsing.
   init(utf8Data inData: Data) {
       let data = (inData as NSData).copy() as! Data
       let buffer = UnsafeBufferPointer(start: UnsafePointer<UInt8>((data as NSData).bytes), count: data.count)
       self.init(buffer: buffer, owner: data)
   }

And this case appears to be going from a String to UnsafeBufferPointer<Uint8>

   /// Creates a `JSONParser` from the code units represented by the `string`.
   ///
   /// The synthesized string is lifetime-extended for the duration of parsing.
   init(string: String) {
       let codePoints = string.nulTerminatedUTF8
       let buffer = codePoints.withUnsafeBufferPointer { nulTerminatedBuffer in
           // don't want to include the nul termination in the buffer - trim it off
           UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1)
       }
       self.init(buffer: buffer, owner: codePoints)
   }

}

I understand pointers from my C/C++/Objective-C days but I don't yet understand the various Swift pointer types. Any help is appreciated.

Note: I don't work for Big Nerd Ranch. I'm just trying to use the code and better understand the various Swift pointer types.

Thanks,
Dave Reed


(Dave Reed) #4

Zach,

Thanks for the fix!

Ah, I think I now see the difference between a UnsafeBufferPointer (it essentially holds the address an array of data) vs. a UnsafePointer (it holds the address where one piece of data is stored), but I'll still need to read the final documentation when it's done.

Dave

···

On Aug 15, 2016, at 9:15 PM, Zach Waldowski via swift-users <swift-users@swift.org> wrote:

Nerd here!

That part of the code ends up not needing to go through the
UnsafeRawPointer API, as it's processing UTF-8 bytes, see also:
<https://github.com/bignerdranch/Freddy/pull/191>.

That being said, good resources for reading about the new pointer system
are:
- [SE-0107]:
<https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md>
- [The Apple API reference], once it's updated:
<https://developer.apple.com/reference/swift>

You can also look up the documentation using the "Documentation and API
Reference" menu in Xcode 8 Beta 6, as it's currently updated.

Sincerely,
  Zachary Waldowski
  zachary@bignerdranch.com

On Mon, Aug 15, 2016, at 03:05 PM, Dave Reed via swift-users wrote:

I'm trying to convert the following code (from the Big Nerd Ranch's
Freddy JSON parser) that works in Xcode 8 beta 5 and convert it to work
with beta 6. Essentially it appears it needs to take a Data object and
convert it to a UnsafeBufferPointer<UInt8> if I understand it correctly.

   /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`.
   ///
   /// If the data is mutable, it is copied before parsing. The data's
   lifetime
   /// is extended for the duration of parsing.
   init(utf8Data inData: Data) {
       let data = (inData as NSData).copy() as! Data
       let buffer = UnsafeBufferPointer(start:
       UnsafePointer<UInt8>((data as NSData).bytes), count: data.count)
       self.init(buffer: buffer, owner: data)
   }

And this case appears to be going from a String to
UnsafeBufferPointer<Uint8>

   /// Creates a `JSONParser` from the code units represented by the
   `string`.
   ///
   /// The synthesized string is lifetime-extended for the duration of
   parsing.
   init(string: String) {
       let codePoints = string.nulTerminatedUTF8
       let buffer = codePoints.withUnsafeBufferPointer {
       nulTerminatedBuffer in
           // don't want to include the nul termination in the buffer -
           trim it off
           UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress,
           count: nulTerminatedBuffer.count - 1)
       }
       self.init(buffer: buffer, owner: codePoints)
   }

}

I understand pointers from my C/C++/Objective-C days but I don't yet
understand the various Swift pointer types. Any help is appreciated.

Note: I don't work for Big Nerd Ranch. I'm just trying to use the code
and better understand the various Swift pointer types.

Thanks,
Dave Reed

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users