what is the right way to yield
a value from a UnsafeMutablePointer.withMemoryRebound(to:capacity:)
call?
i tried this, but it does not compile:
_modify
{
yield &pointer.withMemoryRebound(to: T.self, capacity: 1)
{
$0.pointee
}
}
1 Like
It's better to just yield a raw pointer or a typed view over a raw pointer. But presumably this is needed for C interop. In that case, use a defer
statement to rebind memory since coroutines aren't a thing yet.
struct S {
var pointer: UnsafeMutablePointer<Int64>
var field: UInt64 {
get {
return UInt64(pointer.pointee)
}
_modify {
// Relies on exclusivity to ensure that the memory at self.pointer is not simultaneously
// accessed.
let rawPtr = UnsafeMutableRawPointer(pointer)
let uint64Ptr = rawPtr.bindMemory(to: UInt64.self, capacity: 1)
defer { rawPtr.bindMemory(to: Int64.self, capacity: 1) }
yield &uint64Ptr.pointee
}
}
}
6 Likes
great! by the way, is there any reason to implement a get
instead of a _read
?
1 Like
i’m running into some really strange issues with passing pointers to instance members using &
inside a _modify
subscript.
for some reason, this code works, where the access to &self.core
(which is passed to a C API taking an UnsafeMutablePointer
) in nested inside a function,
_modify
{
let raw:UnsafeMutableRawPointer =
{
guard let raw:UnsafeMutableRawPointer =
Godot.api.functions.godot_array_operator_index(&self.core, .init(index))
.map(UnsafeMutableRawPointer.init(_:))
else
{
fatalError("nil pointer to list element (\(index))")
}
return raw
}()
let pointer:UnsafeMutablePointer<Godot.Variant.Unmanaged> =
raw.bindMemory(to: Godot.Variant.Unmanaged.self, capacity: 1)
defer
{
raw.bindMemory(to: godot_variant.self, capacity: 1)
}
yield &pointer.pointee
}
(Godot.Variant.Unmanaged
is a value type from swift’s perspective, but the C API views it as a reference-counted type. the deinit
on the swift class providing the _modify
subscript manually deinitializes it using a deinitialization API provided by the Godot C framework.)
but if i move this outside the function wrapper, like this
_modify
{
guard let raw:UnsafeMutableRawPointer =
Godot.api.functions.godot_array_operator_index(&self.core, .init(index))
.map(UnsafeMutableRawPointer.init(_:))
else
{
fatalError("nil pointer to list element (\(index))")
}
let pointer:UnsafeMutablePointer<Godot.Variant.Unmanaged> =
raw.bindMemory(to: Godot.Variant.Unmanaged.self, capacity: 1)
defer
{
raw.bindMemory(to: godot_variant.self, capacity: 1)
}
yield &pointer.pointee
}
the program crashes when the _modify
subscript gets called. any idea what’s going on here?
is there any reason to implement a get
instead of a _read
?
If you're already implementing _modify
then I supposed you may as well use _read
. If self
has any references, then that might avoid a retain.
Speaking of references, if that UnsafePointer
points into a class, then you need to extend self
's life time
defer {
raw.bindMemory(...)
withExtendedLifetime(self) {}
}
If lifetime extension doesn't fix the crash, then it appears to be a compiler bug.
1 Like
that was one of the first things i tried, but it did not fix the issue. however, an ordinary set
subscript works, even if the godot_array_operator_index
call is not nested inside another function.
the pointer does not point into the class, but it points to a C-managed object that Swift decrements the reference count of when the deinit
of the Swift wrapper class runs. (the Swift code increments the reference count when it wraps the object). however, the C API passes the object guaranteed (the C API’s equivalent of guaranteed, not Swift guaranteed), so this shouldn’t be the issue.