Skip to content

Commit 0348d61

Browse files
committed
[NFC] Switch BitstreamReader Entrypoints to Use ByteString
ByteString is a more appropriate vocabulary type than Data to use for these entrypoints. TSCBasic traffics in ByteString values, and its representation as an array means that there are reasonable indexing invariants we can rely on with respect to subsequences. This should also enable some clean up in the swift-driver.
1 parent 15db71f commit 0348d61

File tree

5 files changed

+53
-24
lines changed

5 files changed

+53
-24
lines changed

Sources/TSCUtility/Bits.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
*/
1010

1111
import Foundation
12+
import TSCBasic
1213

1314
struct Bits: RandomAccessCollection {
14-
var buffer: Data
15+
var buffer: ByteString
1516

1617
var startIndex: Int { return 0 }
1718
var endIndex: Int { return buffer.count * 8 }
1819

1920
subscript(index: Int) -> UInt8 {
20-
let byte = buffer[index / 8]
21+
let byte = buffer.contents[index / 8]
2122
return (byte >> UInt8(index % 8)) & 1
2223
}
2324

@@ -27,7 +28,7 @@ struct Bits: RandomAccessCollection {
2728
precondition(offset &+ count >= offset)
2829
precondition(offset &+ count <= self.endIndex)
2930

30-
return buffer.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
31+
return buffer.contents.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
3132
let upperBound = offset &+ count
3233
let topByteIndex = upperBound >> 3
3334
var result: UInt64 = 0
@@ -56,10 +57,14 @@ struct Bits: RandomAccessCollection {
5657
self.buffer = buffer
5758
}
5859

59-
init(buffer: Data) {
60+
init(buffer: ByteString) {
6061
self.init(buffer: Bits(buffer: buffer))
6162
}
6263

64+
var isAtStart: Bool {
65+
return offset == buffer.startIndex
66+
}
67+
6368
var isAtEnd: Bool {
6469
return offset == buffer.count
6570
}
@@ -74,14 +79,14 @@ struct Bits: RandomAccessCollection {
7479
return try peek(count)
7580
}
7681

77-
mutating func read(bytes count: Int) throws -> Data {
82+
mutating func read(bytes count: Int) throws -> ArraySlice<UInt8> {
7883
precondition(count >= 0)
7984
precondition(offset & 0b111 == 0)
8085
let newOffset = offset &+ (count << 3)
8186
precondition(newOffset >= offset)
8287
if newOffset > buffer.count { throw Error.bufferOverflow }
8388
defer { offset = newOffset }
84-
return buffer.buffer.dropFirst(offset >> 3).prefix((newOffset - offset) >> 3)
89+
return buffer.buffer.contents.dropFirst(offset >> 3).prefix((newOffset - offset) >> 3)
8590
}
8691

8792
mutating func skip(bytes count: Int) throws {

Sources/TSCUtility/BitstreamReader.swift

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,42 @@
99
*/
1010

1111
import Foundation
12+
import TSCBasic
1213

1314
extension Bitcode {
1415
/// Parse a bitstream from data.
16+
@available(*, deprecated, message: "Use Bitcode.init(bytes:) instead")
1517
public init(data: Data) throws {
1618
precondition(data.count > 4)
17-
let signatureValue = UInt32(Bits(buffer: data).readBits(atOffset: 0, count: 32))
18-
let bitstreamData = data[4..<data.count]
19-
20-
var reader = BitstreamReader(buffer: bitstreamData)
19+
try self.init(bytes: ByteString(data))
20+
}
21+
22+
public init(bytes: ByteString) throws {
23+
precondition(bytes.count > 4)
24+
var reader = BitstreamReader(buffer: bytes)
25+
let signature = try reader.readSignature()
2126
var visitor = CollectingVisitor()
2227
try reader.readBlock(id: BitstreamReader.fakeTopLevelBlockID,
2328
abbrevWidth: 2,
2429
abbrevInfo: [],
2530
visitor: &visitor)
26-
self.init(signature: .init(value: signatureValue),
31+
self.init(signature: signature,
2732
elements: visitor.finalizeTopLevelElements(),
2833
blockInfo: reader.blockInfo)
2934
}
3035

3136
/// Traverse a bitstream using the specified `visitor`, which will receive
3237
/// callbacks when blocks and records are encountered.
38+
@available(*, deprecated, message: "Use Bitcode.read(bytes:using:) instead")
3339
public static func read<Visitor: BitstreamVisitor>(stream data: Data, using visitor: inout Visitor) throws {
3440
precondition(data.count > 4)
35-
let signatureValue = UInt32(Bits(buffer: data).readBits(atOffset: 0, count: 32))
36-
try visitor.validate(signature: .init(value: signatureValue))
41+
try Self.read(bytes: ByteString(data), using: &visitor)
42+
}
3743

38-
let bitstreamData = data[4..<data.count]
39-
var reader = BitstreamReader(buffer: bitstreamData)
44+
public static func read<Visitor: BitstreamVisitor>(bytes: ByteString, using visitor: inout Visitor) throws {
45+
precondition(bytes.count > 4)
46+
var reader = BitstreamReader(buffer: bytes)
47+
try visitor.validate(signature: reader.readSignature())
4048
try reader.readBlock(id: BitstreamReader.fakeTopLevelBlockID,
4149
abbrevWidth: 2,
4250
abbrevInfo: [],
@@ -113,8 +121,14 @@ private struct BitstreamReader {
113121
var blockInfo: [UInt64: BlockInfo] = [:]
114122
var globalAbbrevs: [UInt64: [Bitstream.Abbreviation]] = [:]
115123

116-
init(buffer: Data) {
117-
cursor = Bits.Cursor(buffer: buffer)
124+
init(buffer: ByteString) {
125+
self.cursor = Bits.Cursor(buffer: buffer)
126+
}
127+
128+
mutating func readSignature() throws -> Bitcode.Signature {
129+
precondition(self.cursor.isAtStart)
130+
let bits = try UInt32(self.cursor.read(MemoryLayout<UInt32>.size * 8))
131+
return Bitcode.Signature(value: bits)
118132
}
119133

120134
mutating func readAbbrevOp() throws -> Bitstream.Abbreviation.Operand {
@@ -220,7 +234,7 @@ private struct BitstreamReader {
220234
case .blob:
221235
let length = Int(try cursor.readVBR(6))
222236
try cursor.advance(toBitAlignment: 32)
223-
payload = .blob(try cursor.read(bytes: length))
237+
payload = .blob(try Data(cursor.read(bytes: length)))
224238
try cursor.advance(toBitAlignment: 32)
225239
default:
226240
fatalError()

Sources/TSCUtility/SerializedDiagnostics.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010
import Foundation
11+
import TSCBasic
1112

1213
/// Represents diagnostics serialized in a .dia file by the Swift compiler or Clang.
1314
public struct SerializedDiagnostics {
@@ -42,13 +43,22 @@ public struct SerializedDiagnostics {
4243
/// Serialized diagnostics.
4344
public var diagnostics: [Diagnostic]
4445

46+
@available(*, deprecated, message: "Use SerializedDiagnostics.init(bytes:) instead")
4547
public init(data: Data) throws {
4648
var reader = Reader()
4749
try Bitcode.read(stream: data, using: &reader)
4850
guard let version = reader.versionNumber else { throw Error.noMetadataBlock }
4951
self.versionNumber = version
5052
self.diagnostics = reader.diagnostics
5153
}
54+
55+
public init(bytes: ByteString) throws {
56+
var reader = Reader()
57+
try Bitcode.read(bytes: bytes, using: &reader)
58+
guard let version = reader.versionNumber else { throw Error.noMetadataBlock }
59+
self.versionNumber = version
60+
self.diagnostics = reader.diagnostics
61+
}
5262
}
5363

5464
extension SerializedDiagnostics {

Tests/TSCUtilityTests/BitstreamTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ final class BitstreamTests: XCTestCase {
3737
.appending(components: "Inputs", "serialized.dia")
3838
let contents = try localFileSystem.readFileContents(bitstreamPath)
3939
var visitor = LoggingVisitor()
40-
try Bitcode.read(stream: Data(contents.contents), using: &visitor)
40+
try Bitcode.read(bytes: contents, using: &visitor)
4141
XCTAssertEqual(visitor.log, [
4242
"entering block: 8",
4343
"Record (id: 1, fields: [1], payload: none",
@@ -130,7 +130,7 @@ final class BitstreamTests: XCTestCase {
130130
.appending(components: "Inputs", "serialized.dia")
131131
let contents = try localFileSystem.readFileContents(bitstreamPath)
132132
var visitor = LoggingVisitor()
133-
try Bitcode.read(stream: Data(contents.contents), using: &visitor)
133+
try Bitcode.read(bytes: contents, using: &visitor)
134134
XCTAssertEqual(visitor.log, ["skipping block: 8",
135135
"skipping block: 9",
136136
"skipping block: 9",
@@ -155,7 +155,7 @@ final class BitstreamTests: XCTestCase {
155155
let bitstreamPath = AbsolutePath(#file).parentDirectory
156156
.appending(components: "Inputs", "serialized.dia")
157157
let contents = try localFileSystem.readFileContents(bitstreamPath)
158-
let bitcode = try Bitcode(data: Data(contents.contents))
158+
let bitcode = try Bitcode(bytes: contents)
159159
XCTAssertEqual(bitcode.signature, .init(string: "DIAG"))
160160
XCTAssertEqual(bitcode.elements.count, 18)
161161
guard case .block(let metadataBlock) = bitcode.elements.first else {
@@ -381,7 +381,7 @@ final class BitstreamTests: XCTestCase {
381381
}
382382

383383
var visitor = RoundTripVisitor()
384-
try Bitcode.read(stream: Data(writer.data), using: &visitor)
384+
try Bitcode.read(bytes: ByteString(writer.data), using: &visitor)
385385
}
386386

387387
func testSimpleRecordWrite() {

Tests/TSCUtilityTests/SerializedDiagnosticsTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final class SerializedDiagnosticsTests: XCTestCase {
1818
let serializedDiagnosticsPath = AbsolutePath(#file).parentDirectory
1919
.appending(components: "Inputs", "serialized.dia")
2020
let contents = try localFileSystem.readFileContents(serializedDiagnosticsPath)
21-
let serializedDiags = try SerializedDiagnostics(data: Data(contents.contents))
21+
let serializedDiags = try SerializedDiagnostics(bytes: contents)
2222

2323
XCTAssertEqual(serializedDiags.versionNumber, 1)
2424
XCTAssertEqual(serializedDiags.diagnostics.count, 17)
@@ -66,7 +66,7 @@ final class SerializedDiagnosticsTests: XCTestCase {
6666
let serializedDiagnosticsPath = AbsolutePath(#file).parentDirectory
6767
.appending(components: "Inputs", "clang.dia")
6868
let contents = try localFileSystem.readFileContents(serializedDiagnosticsPath)
69-
let serializedDiags = try SerializedDiagnostics(data: Data(contents.contents))
69+
let serializedDiags = try SerializedDiagnostics(bytes: contents)
7070

7171
XCTAssertEqual(serializedDiags.versionNumber, 1)
7272
XCTAssertEqual(serializedDiags.diagnostics.count, 4)

0 commit comments

Comments
 (0)