Skip to content

Instantly share code, notes, and snippets.

@pbk20191
Last active January 5, 2026 08:37
Show Gist options
  • Select an option

  • Save pbk20191/cde1b573745b6d468b0dc078a1fbd009 to your computer and use it in GitHub Desktop.

Select an option

Save pbk20191/cde1b573745b6d468b0dc078a1fbd009 to your computer and use it in GitHub Desktop.
import Foundation
extension NSSortDescriptor {
// CFBinaryHeapCompareContext does not actullay retains the info field which looks like a bug
func makeBinaryHeap() -> CFBinaryHeap {
// let naturalOrder = NSSortDescriptor(key: "self", ascending: true)
var heapCb = kCFStringBinaryHeapCallBacks
var context = CFBinaryHeapCompareContext()
heapCb.retain = kCFTypeDictionaryKeyCallBacks.retain
heapCb.release = kCFTypeDictionaryKeyCallBacks.release
context.copyDescription = kCFTypeDictionaryKeyCallBacks.copyDescription
heapCb.copyDescription = kCFTypeDictionaryKeyCallBacks.copyDescription
do {
autoreleasepool {
let cf = CFBundleGetBundleWithIdentifier("com.apple.CoreFoundation" as CFString)!
let _cfRetain = CFBundleGetFunctionPointerForName(cf, "CFRetain" as CFString)
let _cfRelease = CFBundleGetFunctionPointerForName(cf, "CFRelease" as CFString)
context.retain = unsafeBitCast(_cfRetain, to: CFTreeRetainCallBack.self)
context.release = unsafeBitCast(_cfRelease, to: CFTreeReleaseCallBack.self)
}
}
context.info = Unmanaged.passUnretained(self).toOpaque()
heapCb.compare = {
let lhs = Unmanaged<NSObjectProtocol>.fromOpaque($0!).takeUnretainedValue()
let rhs = Unmanaged<NSObjectProtocol>.fromOpaque($1!).takeUnretainedValue()
let descriptor = Unmanaged<NSSortDescriptor>.fromOpaque($2!).takeUnretainedValue()
return .init(rawValue: descriptor.compare(lhs, to: rhs).rawValue)!
}
return CFBinaryHeapCreate(nil, 0, &heapCb, &context)!
}
// attach CFAllocator so that it retains the info
func makeBinaryHeap2() -> CFBinaryHeap {
// let naturalOrder = NSSortDescriptor(key: "self", ascending: true)
var allocatorContext = CFAllocatorContext()
allocatorContext.info = Unmanaged.passUnretained(self).toOpaque()
var heapCb = kCFStringBinaryHeapCallBacks
var context = CFBinaryHeapCompareContext()
heapCb.retain = kCFTypeDictionaryKeyCallBacks.retain
heapCb.release = kCFTypeDictionaryKeyCallBacks.release
context.copyDescription = kCFTypeDictionaryKeyCallBacks.copyDescription
heapCb.copyDescription = kCFTypeDictionaryKeyCallBacks.copyDescription
do {
autoreleasepool {
let cf = CFBundleGetBundleWithIdentifier("com.apple.CoreFoundation" as CFString)!
let _cfRetain = CFBundleGetFunctionPointerForName(cf, "CFRetain" as CFString)
let _cfRelease = CFBundleGetFunctionPointerForName(cf, "CFRelease" as CFString)
context.retain = unsafeBitCast(_cfRetain, to: CFTreeRetainCallBack.self)
context.release = unsafeBitCast(_cfRelease, to: CFTreeReleaseCallBack.self)
allocatorContext.retain = context.retain
allocatorContext.release = context.release
allocatorContext.copyDescription = context.copyDescription
}
}
context.info = Unmanaged.passUnretained(self).toOpaque()
allocatorContext.preferredSize = {
let _ = $2
return CFAllocatorGetPreferredSizeForSize(nil, $0, $1)
}
allocatorContext.reallocate = {
let _ = $3
return CFAllocatorReallocate(nil, $0, $1, $2)
}
allocatorContext.allocate = {
let _ = $2
return CFAllocatorAllocate(nil, $0, $1)
}
allocatorContext.deallocate = {
let _ = $1
return CFAllocatorDeallocate(nil, $0)
}
let allocator = CFAllocatorCreate(nil, &allocatorContext).takeRetainedValue()
heapCb.compare = {
let lhs = Unmanaged<NSObjectProtocol>.fromOpaque($0!).takeUnretainedValue()
let rhs = Unmanaged<NSObjectProtocol>.fromOpaque($1!).takeUnretainedValue()
let descriptor = Unmanaged<NSSortDescriptor>.fromOpaque($2!).takeUnretainedValue()
return .init(rawValue: descriptor.compare(lhs, to: rhs).rawValue)!
}
return CFBinaryHeapCreate(allocator, 0, &heapCb, &context)!
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment