mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
These subtests were actually meant to test the raw buffer type itself, not its slice type. So adding an `init(rebasing:)` does what we want. Now that the Collection tests are wired up, these test cases will be run on the slice type automatically. No need to do it here.
494 lines
14 KiB
Swift
494 lines
14 KiB
Swift
// RUN: %target-run-simple-swiftgyb
|
|
// REQUIRES: executable_test
|
|
//
|
|
// Test corner cases specific to UnsafeRawBufferPointer.
|
|
// General Collection behavior tests are in
|
|
// validation-test/stdlib/UnsafeBufferPointer.swift.
|
|
|
|
import StdlibUnittest
|
|
|
|
var UnsafeRawBufferPointerTestSuite = TestSuite("UnsafeRawBufferPointer")
|
|
|
|
// View an in-memory value's bytes.
|
|
// Use copyBytes to overwrite the value's bytes.
|
|
UnsafeRawBufferPointerTestSuite.test("initFromValue") {
|
|
var value1: Int32 = -1
|
|
var value2: Int32 = 0
|
|
// Immutable view of value1's bytes.
|
|
withUnsafeBytes(of: &value1) { bytes1 in
|
|
expectEqual(bytes1.count, 4)
|
|
for b in bytes1 {
|
|
expectEqual(b, 0xFF)
|
|
}
|
|
// Mutable view of value2's bytes.
|
|
withUnsafeMutableBytes(of: &value2) { bytes2 in
|
|
expectEqual(bytes1.count, bytes2.count)
|
|
bytes2.copyBytes(from: bytes1)
|
|
}
|
|
}
|
|
expectEqual(value2, value1)
|
|
}
|
|
|
|
// Test mutability and subscript getter/setters.
|
|
UnsafeRawBufferPointerTestSuite.test("nonmutating_subscript_setter") {
|
|
var value1: Int32 = -1
|
|
var value2: Int32 = 0
|
|
|
|
withUnsafeMutableBytes(of: &value1) { bytes1 in
|
|
withUnsafeMutableBytes(of: &value2) { bytes2 in
|
|
bytes2[0..<bytes2.count] = bytes1[0..<bytes1.count]
|
|
}
|
|
}
|
|
expectEqual(value2, value1)
|
|
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 4)
|
|
defer { buffer.deallocate() }
|
|
buffer.copyBytes(from: [0, 1, 2, 3] as [UInt8])
|
|
let leftBytes = buffer[0..<2]
|
|
|
|
// Subscript assign.
|
|
var rightBytes = buffer[2..<4]
|
|
buffer[2..<4] = leftBytes
|
|
expectEqualSequence(leftBytes, rightBytes)
|
|
|
|
// Subscript assign into a `var` mutable slice.
|
|
buffer.copyBytes(from: [0, 1, 2, 3] as [UInt8])
|
|
rightBytes[2..<4] = leftBytes
|
|
expectEqualSequence(leftBytes, rightBytes)
|
|
}
|
|
|
|
// View an array's elements as bytes.
|
|
// Use copyBytes to overwrite the array element's bytes.
|
|
UnsafeRawBufferPointerTestSuite.test("initFromArray") {
|
|
let array1: [Int32] = [0, 1, 2, 3]
|
|
var array2 = [Int32](repeating: 0, count: 4)
|
|
// Immutable view of array1's bytes.
|
|
array1.withUnsafeBytes { bytes1 in
|
|
expectEqual(bytes1.count, 16)
|
|
for (i, b) in bytes1.enumerated() {
|
|
if i % 4 == 0 {
|
|
expectEqual(Int(b), i / 4)
|
|
}
|
|
else {
|
|
expectEqual(b, 0)
|
|
}
|
|
}
|
|
// Mutable view of array2's bytes.
|
|
array2.withUnsafeMutableBytes { bytes2 in
|
|
expectEqual(bytes1.count, bytes2.count)
|
|
bytes2.copyBytes(from: bytes1)
|
|
}
|
|
}
|
|
expectEqual(array2, array1)
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("initializeMemory(as:from:).underflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 30)
|
|
defer { buffer.deallocate() }
|
|
let source = stride(from: 5 as Int64, to: 0, by: -1)
|
|
var (it,bound) = buffer.initializeMemory(as: Int64.self, from: source)
|
|
let idx = bound.endIndex * MemoryLayout<Int64>.stride
|
|
expectEqual(it.next()!, 2)
|
|
expectEqual(idx, 24)
|
|
let expected: [Int64] = [5,4,3]
|
|
expected.withUnsafeBytes { expectEqualSequence($0,buffer[0..<idx]) }
|
|
expectEqualSequence([5, 4, 3],bound)
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("initializeMemory(as:from:).overflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 30)
|
|
defer { buffer.deallocate() }
|
|
let source: [Int64] = [5, 4, 3, 2, 1]
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
var (it,bound) = buffer.initializeMemory(as: Int64.self, from: source)
|
|
let idx = bound.endIndex * MemoryLayout<Int64>.stride
|
|
expectEqual(it.next()!, 2)
|
|
expectEqual(idx, 24)
|
|
let expected: [Int64] = [5,4,3]
|
|
expected.withUnsafeBytes { expectEqualSequence($0,buffer[0..<idx]) }
|
|
expectEqualSequence([5, 4, 3],bound)
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("initializeMemory(as:from:).exact") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 24)
|
|
defer { buffer.deallocate() }
|
|
let source: [Int64] = [5, 4, 3]
|
|
var (it,bound) = buffer.initializeMemory(as: Int64.self, from: source)
|
|
let idx = bound.endIndex * MemoryLayout<Int64>.stride
|
|
expectNil(it.next())
|
|
expectEqual(idx, buffer.endIndex)
|
|
source.withUnsafeBytes { expectEqualSequence($0,buffer) }
|
|
expectEqualSequence([5, 4, 3],bound)
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("initializeMemory(as:from:).invalidNilPtr") {
|
|
let buffer = UnsafeMutableRawBufferPointer(start: nil, count: 0)
|
|
let source: [Int64] = [5, 4, 3, 2, 1]
|
|
expectCrashLater()
|
|
_ = buffer.initializeMemory(as: Int64.self, from: source)
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("initializeMemory(as:from:).validNilPtr") {
|
|
let buffer = UnsafeMutableRawBufferPointer(start: nil, count: 0)
|
|
let source: [Int64] = []
|
|
var (it, bound) = buffer.initializeMemory(as: Int64.self, from: source)
|
|
let idx = bound.endIndex * MemoryLayout<Int64>.stride
|
|
expectNil(it.next())
|
|
expectEqual(idx, source.endIndex)
|
|
}
|
|
|
|
|
|
// Directly test the byte Sequence produced by withUnsafeBytes.
|
|
UnsafeRawBufferPointerTestSuite.test("withUnsafeBytes.Sequence") {
|
|
let array1: [Int32] = [0, 1, 2, 3]
|
|
array1.withUnsafeBytes { bytes1 in
|
|
// Initialize an array from a sequence of bytes.
|
|
let byteArray = [UInt8](bytes1)
|
|
for (b1, b2) in zip(byteArray, bytes1) {
|
|
expectEqual(b1, b2)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test the empty buffer.
|
|
UnsafeRawBufferPointerTestSuite.test("empty") {
|
|
let emptyBytes = UnsafeRawBufferPointer(start: nil, count: 0)
|
|
for _ in emptyBytes {
|
|
expectUnreachable()
|
|
}
|
|
let emptyMutableBytes = UnsafeMutableRawBufferPointer.allocate(count: 0)
|
|
for _ in emptyMutableBytes {
|
|
expectUnreachable()
|
|
}
|
|
emptyMutableBytes.deallocate()
|
|
}
|
|
|
|
// Store a sequence of integers to raw memory, and reload them as structs.
|
|
// Store structs to raw memory, and reload them as integers.
|
|
UnsafeRawBufferPointerTestSuite.test("reinterpret") {
|
|
struct Pair {
|
|
var x: Int32
|
|
var y: Int32
|
|
}
|
|
let numPairs = 2
|
|
let bytes = UnsafeMutableRawBufferPointer.allocate(
|
|
count: MemoryLayout<Pair>.stride * numPairs)
|
|
defer { bytes.deallocate() }
|
|
|
|
for i in 0..<(numPairs * 2) {
|
|
bytes.storeBytes(of: Int32(i), toByteOffset: i * MemoryLayout<Int32>.stride,
|
|
as: Int32.self)
|
|
}
|
|
let pair1 = bytes.load(as: Pair.self)
|
|
let pair2 = bytes.load(fromByteOffset: MemoryLayout<Pair>.stride,
|
|
as: Pair.self)
|
|
expectEqual(0, pair1.x)
|
|
expectEqual(1, pair1.y)
|
|
expectEqual(2, pair2.x)
|
|
expectEqual(3, pair2.y)
|
|
|
|
bytes.storeBytes(of: Pair(x: -1, y: 0), as: Pair.self)
|
|
for i in 0..<MemoryLayout<Int32>.stride {
|
|
expectEqual(0xFF, bytes[i])
|
|
}
|
|
let bytes2 = UnsafeMutableRawBufferPointer(
|
|
rebasing: bytes[MemoryLayout<Int32>.stride..<bytes.count])
|
|
for i in 0..<MemoryLayout<Int32>.stride {
|
|
expectEqual(0, bytes2[i])
|
|
}
|
|
}
|
|
|
|
// Store, load, subscript, and slice at all valid byte offsets.
|
|
UnsafeRawBufferPointerTestSuite.test("inBounds") {
|
|
let numInts = 4
|
|
let bytes = UnsafeMutableRawBufferPointer.allocate(
|
|
count: MemoryLayout<Int>.stride * numInts)
|
|
defer { bytes.deallocate() }
|
|
|
|
for i in 0..<numInts {
|
|
bytes.storeBytes(
|
|
of: i, toByteOffset: i * MemoryLayout<Int>.stride, as: Int.self)
|
|
}
|
|
for i in 0..<numInts {
|
|
let x = bytes.load(
|
|
fromByteOffset: i * MemoryLayout<Int>.stride, as: Int.self)
|
|
expectEqual(x, i)
|
|
}
|
|
for i in 0..<numInts {
|
|
var x = i
|
|
withUnsafeBytes(of: &x) {
|
|
for (offset, byte) in $0.enumerated() {
|
|
expectEqual(bytes[i * MemoryLayout<Int>.stride + offset], byte)
|
|
}
|
|
}
|
|
}
|
|
let median = (numInts/2 * MemoryLayout<Int>.stride)
|
|
var firstHalf = bytes[0..<median]
|
|
let secondHalf = bytes[median..<bytes.count]
|
|
firstHalf[0..<firstHalf.count] = secondHalf
|
|
expectEqualSequence(firstHalf, secondHalf)
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.get.underflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
|
|
defer { buffer.deallocate() }
|
|
|
|
let bytes = UnsafeRawBufferPointer(rebasing: buffer[1..<2])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Accesses a valid buffer location but triggers a debug bounds check.
|
|
_ = bytes[-1]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.get.overflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
|
|
defer { buffer.deallocate() }
|
|
|
|
let bytes = UnsafeRawBufferPointer(rebasing: buffer[0..<1])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Accesses a valid buffer location but triggers a debug bounds check.
|
|
_ = bytes[1]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.set.underflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
|
|
defer { buffer.deallocate() }
|
|
|
|
var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[1..<2])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Accesses a valid buffer location but triggers a debug bounds check.
|
|
bytes[-1] = 0
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.set.overflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 2)
|
|
defer { buffer.deallocate() }
|
|
|
|
var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[0..<1])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Accesses a valid buffer location but triggers a debug bounds check.
|
|
bytes[1] = 0
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.range.get.underflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
let bytes = UnsafeRawBufferPointer(rebasing: buffer[1..<3])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Accesses a valid buffer location but triggers a debug bounds check.
|
|
_ = bytes[-1..<1]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.range.get.overflow") {
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
let bytes = UnsafeRawBufferPointer(rebasing: buffer[0..<2])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Accesses a valid buffer location but triggers a debug bounds check.
|
|
_ = bytes[1..<3]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.range.set.underflow") {
|
|
var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[1..<3])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Accesses a valid buffer location but triggers a debug bounds check.
|
|
bytes[-1..<1] = bytes[0..<2]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.range.set.overflow") {
|
|
var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
var bytes = UnsafeMutableRawBufferPointer(rebasing: buffer[0..<2])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
|
|
// Performs a valid byte-wise copy but triggers a debug bounds check.
|
|
bytes[1..<3] = bytes[0..<2]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.range.narrow") {
|
|
var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Performs a valid byte-wise copy but triggers a debug bounds check.
|
|
buffer[0..<3] = buffer[0..<2]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("subscript.range.wide") {
|
|
var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Performs a valid byte-wise copy but triggers a debug bounds check.
|
|
buffer[0..<2] = buffer[0..<3]
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("copyBytes.overflow") {
|
|
var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
let bytes = buffer[0..<2]
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Performs a valid byte-wise copy but triggers a debug range size check.
|
|
UnsafeMutableRawBufferPointer(rebasing: bytes).copyBytes(from: buffer)
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("copyBytes.sequence.overflow") {
|
|
var buffer = UnsafeMutableRawBufferPointer.allocate(count: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
let bytes = buffer[0..<2]
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
// Performs a valid byte-wise copy but triggers a debug range size check.
|
|
UnsafeMutableRawBufferPointer(rebasing: bytes).copyBytes(
|
|
from: [0, 1, 2] as [UInt8])
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("load.before")
|
|
.skip(.custom(
|
|
{ !_isDebugAssertConfiguration() },
|
|
reason: "This tests a debug precondition."))
|
|
.code {
|
|
expectCrashLater()
|
|
var x: Int32 = 0
|
|
withUnsafeBytes(of: &x) {
|
|
_ = $0.load(fromByteOffset: -1, as: UInt8.self)
|
|
}
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("load.after")
|
|
.skip(.custom(
|
|
{ !_isDebugAssertConfiguration() },
|
|
reason: "This tests a debug precondition.."))
|
|
.code {
|
|
expectCrashLater()
|
|
var x: Int32 = 0
|
|
withUnsafeBytes(of: &x) {
|
|
_ = $0.load(as: UInt64.self)
|
|
}
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("store.before")
|
|
.skip(.custom(
|
|
{ !_isDebugAssertConfiguration() },
|
|
reason: "This tests a debug precondition.."))
|
|
.code {
|
|
expectCrashLater()
|
|
var x: Int32 = 0
|
|
withUnsafeMutableBytes(of: &x) {
|
|
$0.storeBytes(of: UInt8(0), toByteOffset: -1, as: UInt8.self)
|
|
}
|
|
}
|
|
UnsafeRawBufferPointerTestSuite.test("store.after")
|
|
.skip(.custom(
|
|
{ !_isDebugAssertConfiguration() },
|
|
reason: "This tests a debug precondition.."))
|
|
.code {
|
|
expectCrashLater()
|
|
var x: Int32 = 0
|
|
withUnsafeMutableBytes(of: &x) {
|
|
$0.storeBytes(of: UInt64(0), as: UInt64.self)
|
|
}
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("copy.bytes.overflow")
|
|
.skip(.custom(
|
|
{ !_isDebugAssertConfiguration() },
|
|
reason: "This tests a debug precondition.."))
|
|
.code {
|
|
expectCrashLater()
|
|
var x: Int64 = 0
|
|
var y: Int32 = 0
|
|
withUnsafeBytes(of: &x) { srcBytes in
|
|
withUnsafeMutableBytes(of: &y) { destBytes in
|
|
destBytes.copyBytes(
|
|
from: UnsafeMutableRawBufferPointer(mutating: srcBytes))
|
|
}
|
|
}
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("copy.sequence.overflow")
|
|
.skip(.custom(
|
|
{ !_isDebugAssertConfiguration() },
|
|
reason: "This tests a debug precondition.."))
|
|
.code {
|
|
expectCrashLater()
|
|
var x: Int64 = 0
|
|
var y: Int32 = 0
|
|
withUnsafeBytes(of: &x) { srcBytes in
|
|
withUnsafeMutableBytes(of: &y) { destBytes in
|
|
destBytes.copyBytes(from: srcBytes)
|
|
}
|
|
}
|
|
}
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("copy.overlap") {
|
|
let bytes = UnsafeMutableRawBufferPointer.allocate(count: 4)
|
|
// Right Overlap
|
|
bytes[0] = 1
|
|
bytes[1] = 2
|
|
bytes[1..<3] = bytes[0..<2]
|
|
expectEqual(1, bytes[1])
|
|
expectEqual(2, bytes[2])
|
|
// Left Overlap
|
|
bytes[1] = 2
|
|
bytes[2] = 3
|
|
bytes[0..<2] = bytes[1..<3]
|
|
expectEqual(2, bytes[0])
|
|
expectEqual(3, bytes[1])
|
|
// Disjoint
|
|
bytes[2] = 2
|
|
bytes[3] = 3
|
|
bytes[0..<2] = bytes[2..<4]
|
|
expectEqual(2, bytes[0])
|
|
expectEqual(3, bytes[1])
|
|
bytes[0] = 0
|
|
bytes[1] = 1
|
|
bytes[2..<4] = bytes[0..<2]
|
|
expectEqual(0, bytes[2])
|
|
expectEqual(1, bytes[3])
|
|
}
|
|
|
|
runAllTests()
|