Skip to content

Instantly share code, notes, and snippets.

@yangyubo
Last active August 10, 2019 09:11
Show Gist options
  • Save yangyubo/a9d681f29df3a1a2cab065a0b1b41731 to your computer and use it in GitHub Desktop.
Save yangyubo/a9d681f29df3a1a2cab065a0b1b41731 to your computer and use it in GitHub Desktop.
Passing an Array of Strings from Swift to C
// Support for array of C strings
// https://oleb.net/blog/2016/10/swift-array-of-c-strings/
// https://github.com/apple/swift/blob/master/stdlib/private/SwiftPrivate/SwiftPrivate.swift
private func scan<
S : Sequence, U
>(_ seq: S, _ initial: U, _ combine: (U, S.Iterator.Element) -> U) -> [U] {
var result: [U] = []
result.reserveCapacity(seq.underestimatedCount)
var runningResult = initial
for element in seq {
runningResult = combine(runningResult, element)
result.append(runningResult)
}
return result
}
func withArrayOfCStrings<R>(
_ args: [String], _ body: ([UnsafeMutablePointer<CChar>?]) -> R
) -> R {
let argsCounts = Array(args.map { $0.utf8.count + 1 })
let argsOffsets = [ 0 ] + scan(argsCounts, 0, +)
let argsBufferSize = argsOffsets.last!
var argsBuffer: [UInt8] = []
argsBuffer.reserveCapacity(argsBufferSize)
for arg in args {
argsBuffer.append(contentsOf: arg.utf8)
argsBuffer.append(0)
}
return argsBuffer.withUnsafeMutableBufferPointer {
(argsBuffer) in
let ptr = UnsafeMutableRawPointer(argsBuffer.baseAddress!).bindMemory(
to: CChar.self, capacity: argsBuffer.count)
var cStrings: [UnsafeMutablePointer<CChar>?] = argsOffsets.map { ptr + $0 }
cStrings[cStrings.count - 1] = nil
return body(cStrings)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment