Hello,
I want to test that a blob loaded from SQLite has not been copied:
// Test the Row.dataNoCopy(atIndex:) method.
// It should not copy the blob buffer loaded by SQLite.
let rows = try Row.fetchCursor(db, "SELECT * FROM datas")
while let row = try rows.next() {
// The pointer to the blob loaded by SQLite (using C API)
let sqlitePointer: UnsafeRawPointer? = sqlite3_column_blob(row.sqliteStatement, 0)
// Load that blob into a Data value with the tested method.
// This internally calls Data(bytesNoCopy:count:deallocator:)
// with the same blob buffer as above.
let data: Data = row.dataNoCopy(atIndex: 0)!
data.withUnsafeBytes { buffer in
// Test that data has not been copied
XCTAssertEqual(buffer.baseAddress, sqlitePointer)
}
}
This test fails, with Swift 5, with the following error:
XCTAssertEqual failed: ("Optional(0x00007ffeefbfc760)")
is not equal to ("Optional(0x0000000103022200)")
With the Swift 4.2 compiler (Xcode 10.1), the test passes.
Do I write my test in a bad way, or is it a regression in the Foundation library shipped with the latest Swift 5 snapshot (06/02/2019)?
Actually, I really can't manage to see Data(bytesNoCopy:count:deallocator:) in action:
let data1 = Data([0])
data1.withUnsafeBytes { buffer1 in
let data2 = Data(
bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer1.baseAddress!),
count: buffer1.count,
deallocator: .none)
data2.withUnsafeBytes { buffer2 in
// Unexpectedly (?) fails
assert(buffer1.baseAddress == buffer2.baseAddress)
}
}
let nsData1 = NSData(data: data1)
let nsData2 = NSData(
bytesNoCopy: UnsafeMutableRawPointer(mutating: nsData1.bytes),
length: nsData1.count,
freeWhenDone: false)
// Expectedly passes
assert(nsData1.bytes == nsData2.bytes)
Usually the "NoCopy" label is only a hint. The internal _Representation can store an InlineData with up to 14 bytes (64-bit arch) or 6 bytes (32-bit arch). Your last example should succeed with let data1 = Data(repeating: 0, count: 15).
2 Likes
Your prediction is 100% accurate, Ben, thank you! 15 is indeed the threshold that triggers the assertions to pass. 
I've learned something today. Now I do have to test that the library actually helps users spare memory: I'll test with bigger data chunks guaranteed to be somewhere on the heap. Thank you again!
2 Likes