I built a binary search tree with Swift and wanted to maximise performance, inserting nodes had a lot of retain/release overhead so I tried to reduce it with Unamanged as advised in optimisation tips.
First, I just wanted to be 100% sure : can I avoid using withExtendedLifetime(T)
if I know the reference count of T won't drop to 0 ?
The docs mentions _withUnsafeGuaranteedRef
saying :
Use the unmanaged reference in a call/variable access. The use of _withUnsafeGuaranteedRef allows the compiler to remove the ultimate retain/release across the call/access.
Does this mean that, given type Foo
has a bar
property and baz
is a Unmanaged<Foo>
, calling :
baz._withUnsafeGuaranteedRef { $0.bar }
Will cause no retain/release to the object referenced by $0, and won't cause retain/release to bar either ?
My issue is that using _withUnsafeGuaranteedRef
causes a performance regression, in my tests :
if let existingChild = currentNode.takeUnretainedValue().rhs {
Is much faster than :
if let existingChild = currentNode._withUnsafeGuaranteedRef { $0.rhs }
I don't understand why.
Here is the full code example, do you think I am using Unamanged correctly ?
func insert(word: String, position: Int) {
var currentNode = Unmanaged.passUnretained(self)
var wasInserted = false
repeat {
if word < currentNode.takeUnretainedValue().word {
if let existingChild = currentNode.takeUnretainedValue().lhs {
currentNode = Unmanaged.passUnretained(existingChild)
} else {
let newNode = Node(word: word, occurences: [position])
newNode.parent = currentNode.takeUnretainedValue()
currentNode.takeUnretainedValue().lhs = newNode
wasInserted = true
}
} else if word > currentNode.takeUnretainedValue().word {
if let existingChild = currentNode.takeUnretainedValue().rhs {
currentNode = Unmanaged.passUnretained(existingChild)
} else {
let newNode = Node(word: word, occurences: [position])
newNode.parent = currentNode.takeUnretainedValue()
currentNode.takeUnretainedValue().rhs = newNode
wasInserted = true
}
} else {
currentNode.takeUnretainedValue().occurences.insert(position)
wasInserted = true
}
} while !wasInserted
}
Thank you !