in Sources/TSCUtility/BitstreamReader.swift [155:219]
mutating func withAbbreviatedRecord(
_ abbrev: Bitstream.Abbreviation,
body: (BitcodeElement.Record) throws -> Void
) throws {
let code = try readSingleAbbreviatedRecordOperand(abbrev.operands.first!)
let lastOperand = abbrev.operands.last!
let lastRegularOperandIndex: Int = abbrev.operands.endIndex - (lastOperand.isPayload ? 1 : 0)
// Safety: `lastRegularOperandIndex` is always at least 1. An abbreviation
// is required by the format to contain at least one operand. If that last
// operand is a payload (and thus we subtracted one from the total number of
// operands above), then that must mean it is either a trailing array
// or trailing blob. Both of these are preceded by their length field.
let fields = UnsafeMutableBufferPointer<UInt64>.allocate(capacity: lastRegularOperandIndex - 1)
defer { fields.deallocate() }
for (idx, op) in abbrev.operands[1..<lastRegularOperandIndex].enumerated() {
fields[idx] = try readSingleAbbreviatedRecordOperand(op)
}
let payload: BitcodeElement.Record.Payload
if !lastOperand.isPayload {
payload = .none
} else {
switch lastOperand {
case .array(let element):
let length = try cursor.readVBR(6)
if case .char6 = element {
// FIXME: Once the minimum deployment target bumps to macOS 11, use
// the more ergonomic stdlib API everywhere.
if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
payload = try .char6String(String(unsafeUninitializedCapacity: Int(length)) { buffer in
for i in 0..<Int(length) {
buffer[i] = try UInt8(readSingleAbbreviatedRecordOperand(element))
}
return Int(length)
})
} else {
let buffer = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: Int(length))
defer { buffer.deallocate() }
for i in 0..<Int(length) {
buffer[i] = try UInt8(readSingleAbbreviatedRecordOperand(element))
}
payload = .char6String(String(decoding: buffer, as: UTF8.self))
}
} else {
var elements = [UInt64]()
for _ in 0..<length {
elements.append(try readSingleAbbreviatedRecordOperand(element))
}
payload = .array(elements)
}
case .blob:
let length = Int(try cursor.readVBR(6))
try cursor.advance(toBitAlignment: 32)
payload = .blob(try cursor.read(bytes: length))
try cursor.advance(toBitAlignment: 32)
default:
fatalError()
}
}
return try body(.init(id: code, fields: UnsafeBufferPointer(fields), payload: payload))
}