> On Dec 1, 2016, at 3:29 AM, Patrick Pijnappel via swift-dev
> wrote:
>
> I'm implementing a COW big int type but am running into problems with
> non-mutating functions (e.g. the + operator). Simplified example code below
> shows AFAIK the default way to implement COW, but the non-mutating method
> doesn't identify the reference as unique (even with -O), resulting in a
> needless copy.
>
> I've tried everything I could think of, but only inout parameters seem to
> work. How does the standard library do this, for e.g. String + String?
>
> struct Foo {
> var storage = Storage()
>
> class Storage { var x = 0 }
>
> init(_ x: Int) { storage.x = x }
>
> mutating func negate() {
> if !isKnownUniquelyReferenced() {
> print("Copy")
> }
> storage.x = -storage.x
> }
>
> func negated() -> Foo {
> var result = self // This counts as a second reference
> result.negate()
> return result
> }
> }
>
> func test() {
> var a = Foo(5)
> a.negate()
> print(a.storage.x)
>
> let b = Foo(5)
> let c = b.negated()
> print(c.storage.x)
> }
>
> test()
Unfortunately, the compiler currently always passes the 'self' parameter of a
nonmutating method with a caller-release convention, meaning that any local
mutable copy necessarily needs to retain a local copy and can't consume the
incoming 'self' value, and there's currently no way to override this.
Theoretically, defining `negated` as a free function should enable this
optimization, since non-'self' parameters are passed callee-release and can be
consumed:
func negate(foo: Foo) -> Foo {
var result = foo
result.negate()
return result
}
though from what I've seen, the ARC optimizer doesn't always successfully
shorten the lifetime of parameters enough to turn the "result = foo" into a
move, which is a known bug.
-Joe
___
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev