How to malloc in Swift 3


(Gerriet M. Denkmann) #1

This used to work in Swift 2.2:

var bitfield: UnsafeMutablePointer<UInt8>?
bitfield = UnsafeMutablePointer<UInt8>( malloc( 888 ) )

How is this written in Swift 3.0?

Gerriet.


(Svein Halvor Halvorsen) #2

var bitfield: UnsafeMutablePointer<UInt8>?
bitfield = UnsafeMutablePointer<UInt8>.allocate(capacity: 888)

···

23. sep. 2016 kl. 10.47 skrev Gerriet M. Denkmann via swift-users <swift-users@swift.org>:

This used to work in Swift 2.2:

var bitfield: UnsafeMutablePointer<UInt8>?
bitfield = UnsafeMutablePointer<UInt8>( malloc( 888 ) )

How is this written in Swift 3.0?

Gerriet.

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


(Gerriet M. Denkmann) #3

To answer my own question:
This works:
var bitfield: UnsafeMutableRawPointer
bitfield = UnsafeMutableRawPointer( malloc(888))

But then this stops working:
let theByte = self.bitfield[ 5 ]

Somehow the bitfield must know that it is a field of bytes (not shorts, ints or whatever). But how?

Gerriet.

···

On 23 Sep 2016, at 15:47, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

This used to work in Swift 2.2:

var bitfield: UnsafeMutablePointer<UInt8>?
bitfield = UnsafeMutablePointer<UInt8>( malloc( 888 ) )

How is this written in Swift 3.0?


(Gerriet M. Denkmann) #4

var bitfield: UnsafeMutablePointer<UInt8>?
bitfield = UnsafeMutablePointer<UInt8>.allocate(capacity: 888)

Excellent!
I see that “- Postcondition: The pointee is allocated, but not initialized.”

What about calloc then? Or use allocate and do a memset afterwards?

Thanks a lot for your help!

Kind regards,

Gerriet.

···

On 23 Sep 2016, at 17:08, Svein Halvor Halvorsen via swift-users <swift-users@swift.org> wrote:

23. sep. 2016 kl. 10.47 skrev Gerriet M. Denkmann via swift-users <swift-users@swift.org>:

This used to work in Swift 2.2:

var bitfield: UnsafeMutablePointer<UInt8>?
bitfield = UnsafeMutablePointer<UInt8>( malloc( 888 ) )

How is this written in Swift 3.0?

Gerriet.

_______________________________________________
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


(Joe Groff) #5

The RawPointer types provide methods that can load a value with a given offset and type for you. IIRC, `bitfield.load(fromByteOffset: 0, as: UInt8.self)` will do what you want.

-Joe

···

On Sep 23, 2016, at 1:55 AM, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

On 23 Sep 2016, at 15:47, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

This used to work in Swift 2.2:

var bitfield: UnsafeMutablePointer<UInt8>?
bitfield = UnsafeMutablePointer<UInt8>( malloc( 888 ) )

How is this written in Swift 3.0?

To answer my own question:
This works:
var bitfield: UnsafeMutableRawPointer
bitfield = UnsafeMutableRawPointer( malloc(888))

But then this stops working:
let theByte = self.bitfield[ 5 ]

Somehow the bitfield must know that it is a field of bytes (not shorts, ints or whatever). But how?


(Quinn “The Eskimo!”) #6

For trivial data types (like UInt8) this will work, but if you want to follow the rules I recommend reading the following:

* UnsafeRawPointer Migration

<https://swift.org/migration-guide/se-0107-migrate.html>

* SE-0107 “UnsafeRawPointer API”

<https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md>

Spoiler: that’ll point you to `initialize(to:count:)` (-:

                   * * *

Also, why are you manually allocating this rather than using [UInt8]? The latter is easier, safer, and likely to have similar levels of efficiency.

Share and Enjoy

···

On 23 Sep 2016, at 11:29, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

What about calloc then? Or use allocate and do a memset afterwards?

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Jens Persson) #7

What is the difference between:
ptr.storeBytes(of: x, toByteOffset: offset, as: type(of: x))
ptr.advanced(by: offset).assumingMemoryBound(to: type(of: x)).pointee = x
?
I noticed that the former traps if storing to a misaligned offset while the
latter is happy to do that, and I saw it mentioned as a requirement in the
documentation, but other than that I'm not sure what would be the pros and
cons of using the former / latter?
/Jens

···

On Fri, Sep 23, 2016 at 10:23 PM, Joe Groff via swift-users < swift-users@swift.org> wrote:

> On Sep 23, 2016, at 1:55 AM, Gerriet M. Denkmann via swift-users < > swift-users@swift.org> wrote:
>
>
>> On 23 Sep 2016, at 15:47, Gerriet M. Denkmann via swift-users < > swift-users@swift.org> wrote:
>>
>> This used to work in Swift 2.2:
>>
>> var bitfield: UnsafeMutablePointer<UInt8>?
>> bitfield = UnsafeMutablePointer<UInt8>( malloc( 888 ) )
>>
>> How is this written in Swift 3.0?
>
> To answer my own question:
> This works:
> var bitfield: UnsafeMutableRawPointer
> bitfield = UnsafeMutableRawPointer( malloc(888))
>
> But then this stops working:
> let theByte = self.bitfield[ 5 ]
>
> Somehow the bitfield must know that it is a field of bytes (not shorts,
ints or whatever). But how?

The RawPointer types provide methods that can load a value with a given
offset and type for you. IIRC, `bitfield.load(fromByteOffset: 0, as:
UInt8.self)` will do what you want.

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


(Gerriet M. Denkmann) #8

What about calloc then? Or use allocate and do a memset afterwards?

For trivial data types (like UInt8) this will work, but if you want to follow the rules I recommend reading the following:

* UnsafeRawPointer Migration

<https://swift.org/migration-guide/se-0107-migrate.html>

* SE-0107 “UnsafeRawPointer API”

<https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md>

Spoiler: that’ll point you to `initialize(to:count:)` (-:

Thanks for the links.
By the way: I had already tried to use `initialize(to:count:)` before, but I used it as a replacement of allocate, which the compiler did not really like.
Since reading these documents I know that I have to use it after allocate, not instead of.

In dealloc I had before:
  free( bitfield )
which, to my surprise, the compiler did NOT warn about (should there be a warning?)
I have since replace this with:
  bitfield.deallocate(capacity: numberUsedInAllocate )

                  * * *

Also, why are you manually allocating this rather than using [UInt8]? The latter is easier, safer, and likely to have similar levels of efficiency.

I just tried this: [UInt8] turns out to be nearly 10% slower compared to: UnsafeMutablePointer<UInt8>.allocate(capacity:).

Probably depends on the use case, whether 10% less performance is worth the easier and safer.
I am trying to compare Swift to ObjC classes (which use malloc), so it would not be a fair comparison if the Swift class has to use an UInt8 array.

Kind regards,

Gerriet.

···

On 23 Sep 2016, at 19:41, Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:
On 23 Sep 2016, at 11:29, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:


(Joe Groff) #9

cc'ing Andy, who's the expert on this. AIUI, the former does not semantically bind the memory to the type being stored—informally, it has "memcpy semantics"—whereas the latter *will* bind the memory to a type, which will require all other loads and stores derived from the same pointer to remain of the same type. Neither API officially supports unaligned loads or stores yet; if one crashes and the other doesn't, that's an accident.

-Joe

···

On Sep 23, 2016, at 2:20 PM, Jens Persson <jens@bitcycle.com> wrote:

What is the difference between:
ptr.storeBytes(of: x, toByteOffset: offset, as: type(of: x))
ptr.advanced(by: offset).assumingMemoryBound(to: type(of: x)).pointee = x
?
I noticed that the former traps if storing to a misaligned offset while the latter is happy to do that, and I saw it mentioned as a requirement in the documentation, but other than that I'm not sure what would be the pros and cons of using the former / latter?


(Andrew Trick) #10

storeBytes(of:as:) is an untyped memory operation. e.g. you could use it store a UInt32 to an Float’s location without binding memory.

assumingMemoryBound(to:) gives you a typed pointer, that you the programmer must guarantee is the correct type for that memory location. If you use this to get a UInt32 pointer into a Float’s location, you get undefined behavior as soon as you access the pointee.

storeBytes traps on misaligned access because memory is being reinterpreted making it easy to violate the alignment precondition.

UnsafePointer<T>.pointee never checked the alignment precondition because normally you wouldn’t need to and it’s supposed to be zero overhead.

assumingMemoryBound(to:) does not check alignment because it isn’t undefined behavior until the pointer is accessed and it’s supposed to be zero overhead.

Basically assumingMemoryBound(to:) is the one backdoor that we have for force casting pointers. The “assuming” should clue the programmer in that they really need to know what they’re doing before using it.

https://swift.org/migration-guide/se-0107-migrate.html#api-for-binding-memory-types-and-pointer-conversion

-Andy

···

On Sep 23, 2016, at 2:23 PM, Joe Groff <jgroff@apple.com> wrote:

On Sep 23, 2016, at 2:20 PM, Jens Persson <jens@bitcycle.com> wrote:

What is the difference between:
ptr.storeBytes(of: x, toByteOffset: offset, as: type(of: x))
ptr.advanced(by: offset).assumingMemoryBound(to: type(of: x)).pointee = x
?
I noticed that the former traps if storing to a misaligned offset while the latter is happy to do that, and I saw it mentioned as a requirement in the documentation, but other than that I'm not sure what would be the pros and cons of using the former / latter?

cc'ing Andy, who's the expert on this. AIUI, the former does not semantically bind the memory to the type being stored—informally, it has "memcpy semantics"—whereas the latter *will* bind the memory to a type, which will require all other loads and stores derived from the same pointer to remain of the same type. Neither API officially supports unaligned loads or stores yet; if one crashes and the other doesn't, that's an accident.

-Joe