-
-
Notifications
You must be signed in to change notification settings - Fork 24
Open
Description
In @ricobeck's presentation today we looked at this part:
PlaydateKit/Sources/PlaydateKit/Core/Sound.swift
Lines 227 to 237 in 03ee2e1
@discardableResult public func setSample(path: UnsafePointer<CChar>) -> Bool { | |
if let samplePointer { | |
sample.freeSample(samplePointer) | |
} | |
samplePointer = sample.load(path) | |
guard samplePointer != nil else { return false } | |
sampleplayer.setSample(playerPointer, samplePointer) | |
return true | |
} |
Suggestion
What do you think about this:
We wrap a manually memory-managed object like "Sample" in a RAII (Resource Acquisition Is Initialization) class. (I know it's a C++ technique https://en.cppreference.com/w/cpp/language/raii but works with C as well to hide pointer mangement)
Before
@discardableResult public func setSample(path: UnsafePointer<CChar>) -> Bool {
// Every change to self.sample needs to care about memory
if let samplePointer {
sample.freeSample(samplePointer)
}
// Replacing can fail (but the other pointer is already gone)
samplePointer = sample.load(path)
guard samplePointer != nil else { return false }
// Still using raw pointers after the load, also for playerPointer
sampleplayer.setSample(playerPointer, samplePointer)
return true
}
After
@discardableResult public func setSample(path: UnsafePointer<CChar>) -> Bool {
guard let newSample = Sample(loadFromPath: path) else { return false }
self.sample = newSample
newSample.withUnsafePointer { samplePointer in
sampleplayer.setSample(playerPointer, samplePointer)
}
return true
}
Approach
Pseudoswift sketch:
final class Sample {
private let pointer: OpaquePointer
init?(loadFromPath path: UnsafePointer<CChar>) {
let pointer = sample.load(path)
guard pointer != nil else { return nil }
self.pointer = pointer
}
deinit {
sample.freeSample(pointer)
}
func withUnsafePointer(_ body: (OpaquePointer) -> Void) {
body(pointer)
}
}
- Upside: if you have a
Sample
, your pointer is still alive, and we can use ARC to manageSample
's lifetime. So no calls to 'free' outside of where the opaque pointers are privately known. - Downside: It's another heap allocation.
oliverepper
Metadata
Metadata
Assignees
Labels
No labels