Avoiding an extra copy withUnsafeBytes


(Ray Fix) #1

To compute a hash, I want to loop through bytes of a trivial type. To get the bytes, I use withUnsafeBytes hands me a rawBufferPointer collection type. Great!

However this call also requires that the "of arg" be declared as a “var" instead of “let” because it is inout. So to do it generically, it forces me to make a copy to some var storage.

Since I am using withUnsafeBytes and not withUnsafeMutableBytes, though, it doesn’t seem like this copy should be necessary. Is there some way to avoid it? Is it something the compiler should be able to reason about and therefore elide? Possibly a future evolution (and something for that list)?

On a side note, wouldn’t it be cool if there where a way to enforce that a type was trivial?

Then one could write code like:

func consume<T: Trivial>(value: T) {
  var copy = value
  withUnsafeMutableBytes(of: &copy) { rawBufferPointer in
    // something interesting
  }
}

Always appreciate the great insights I get here.
Thanks as always. Best wishes,
Ray


(Joe Groff) #2

There's no fundamental reason it needs a var; see https://bugs.swift.org/browse/SR-3679. The formal copy can often be elided by the LLVM optimizer in most cases, though unfortunately not all (https://llvm.org/bugs/show_bug.cgi?id=31697 is one such case). There is some benefit to encouraging people to use the `inout` version when possible in our current language, though in the fullness of time, the operand would be better modeled as an "immutable borrow" in the ownership model.

-Joe

···

On Jan 26, 2017, at 7:03 AM, Ray Fix via swift-users <swift-users@swift.org> wrote:

To compute a hash, I want to loop through bytes of a trivial type. To get the bytes, I use withUnsafeBytes hands me a rawBufferPointer collection type. Great!

However this call also requires that the "of arg" be declared as a “var" instead of “let” because it is inout. So to do it generically, it forces me to make a copy to some var storage.

Since I am using withUnsafeBytes and not withUnsafeMutableBytes, though, it doesn’t seem like this copy should be necessary. Is there some way to avoid it? Is it something the compiler should be able to reason about and therefore elide? Possibly a future evolution (and something for that list)?

On a side note, wouldn’t it be cool if there where a way to enforce that a type was trivial?

Then one could write code like:

func consume<T: Trivial>(value: T) {
  var copy = value
  withUnsafeMutableBytes(of: &copy) { rawBufferPointer in
    // something interesting
  }
}

Always appreciate the great insights I get here.
Thanks as always. Best wishes,