mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This precondition checks to make sure that the content-providing collection isn't larger than the allocated buffer, but was preventing using a buffer that is the exact same size as the collection.
1297 lines
42 KiB
Swift
1297 lines
42 KiB
Swift
// RUN: %target-run-simple-swiftgyb
|
|
// REQUIRES: executable_test
|
|
|
|
// FIXME: The optimized-build behavior of UnsafeBufferPointer bounds/overflow
|
|
// checking cannot be tested. The standard library always compiles with debug
|
|
// checking enabled, so the behavior of the optimized test depends on whether
|
|
// the inlining heuristics decide to inline these methods. To fix this, we need
|
|
// a way to force @inlinable UnsafeBufferPointer methods to be emitted inside
|
|
// the client code, and thereby subject the stdlib implementation to the test
|
|
// case's compile options.
|
|
//
|
|
// REQUIRES: swift_test_mode_optimize_none
|
|
|
|
import StdlibUnittest
|
|
import StdlibCollectionUnittest
|
|
|
|
// Tests
|
|
|
|
func allocateForRawBuffer(count: Int) -> UnsafeMutableRawPointer {
|
|
return UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1)
|
|
}
|
|
func allocateForBuffer<T>(count: Int) -> UnsafeMutablePointer<T> {
|
|
return UnsafeMutablePointer<T>.allocate(capacity: count)
|
|
}
|
|
func deallocateForRawBuffer(
|
|
_ memory: UnsafeMutableRawPointer, count: Int
|
|
) {
|
|
memory.deallocate()
|
|
}
|
|
func deallocateForBuffer<T>(
|
|
_ memory: UnsafeMutablePointer<T>, count: Int
|
|
) {
|
|
memory.deallocate()
|
|
}
|
|
|
|
// Initialize memory with arbitrary equatable, comparable values.
|
|
func initUnsafeRawBufferPointer(_ b: UnsafeMutableRawBufferPointer) {
|
|
_ = b.initializeMemory(as: UInt8.self, from: UInt8(0)..<numericCast(b.count))
|
|
}
|
|
func initUnsafeBufferPointer(_ b: UnsafeMutableBufferPointer<Float>) {
|
|
_ = b.initialize(from: (0..<b.count).lazy.map {Float($0)})
|
|
}
|
|
|
|
// Test Suites
|
|
|
|
var UnsafeBufferPointerTestSuite = TestSuite("UnsafeBufferPointer")
|
|
var UnsafeMutableBufferPointerTestSuite = TestSuite("UnsafeMutableBufferPointer")
|
|
var UnsafeRawBufferPointerTestSuite = TestSuite("UnsafeRawBufferPointer")
|
|
var UnsafeMutableRawBufferPointerTestSuite = TestSuite("UnsafeMutableRawBufferPointer")
|
|
|
|
% for (SelfName, IsMutable, IsRaw, SelfType, PointerType) in [
|
|
% ('UnsafeBufferPointer', False, False, 'UnsafeBufferPointer<Float>', 'UnsafePointer<Float>'),
|
|
% ('UnsafeMutableBufferPointer', True, False, 'UnsafeMutableBufferPointer<Float>', 'UnsafeMutablePointer<Float>'),
|
|
% ('UnsafeRawBufferPointer', False, True, 'UnsafeRawBufferPointer', 'UnsafeRawPointer'),
|
|
% ('UnsafeMutableRawBufferPointer', True, True, 'UnsafeMutableRawBufferPointer', 'UnsafeMutableRawPointer')
|
|
% ]:
|
|
% Raw = 'Raw' if IsRaw else ''
|
|
% Element = 'UInt8' if IsRaw else 'Float'
|
|
|
|
${SelfName}TestSuite.test("AssociatedTypes") {
|
|
expectRandomAccessCollectionAssociatedTypes(
|
|
collectionType: ${SelfType}.self,
|
|
% if IsRaw:
|
|
iteratorType: ${SelfType}.Iterator.self,
|
|
% else:
|
|
iteratorType: UnsafeBufferPointer<Float>.Iterator.self,
|
|
% end
|
|
subSequenceType: Slice<${SelfType}>.self,
|
|
indexType: Int.self,
|
|
indicesType: Range<Int>.self)
|
|
|
|
expect${'Mutable' if IsMutable else ''}CollectionType(${SelfType}.self)
|
|
}
|
|
|
|
${SelfName}TestSuite.test("rebasing") {
|
|
let rawbuffer = UnsafeMutableRawBufferPointer.allocate(
|
|
byteCount: 4 * MemoryLayout<Int>.stride, alignment: MemoryLayout<UInt>.alignment)
|
|
defer { rawbuffer.deallocate() }
|
|
|
|
rawbuffer.copyBytes(from: [0, 1, 2, 3])
|
|
|
|
% if IsRaw:
|
|
let buffer = rawbuffer
|
|
% else:
|
|
let intPtr = rawbuffer.baseAddress!.bindMemory(to: Int.self, capacity: 4)
|
|
let buffer = UnsafeMutableBufferPointer(start: intPtr, count: 4)
|
|
% end
|
|
|
|
for i in buffer.indices {
|
|
let slice = buffer[i..<buffer.endIndex]
|
|
let rebased = ${SelfName}(rebasing: slice)
|
|
expectEqual(rebased.startIndex, 0)
|
|
expectEqual(rebased.endIndex, rebased.count)
|
|
expectEqual(rebased.endIndex, buffer.endIndex - i)
|
|
expectEqual(rebased[0], slice[i])
|
|
if rebased.count > 1 {
|
|
expectEqual(rebased[1], slice[i + 1])
|
|
|
|
// Rebase again. Tests Mutable->Immutable initializer
|
|
// and an rvalue slice with literal indices.
|
|
let rebased2 = ${SelfName}(rebasing: rebased[1..<2])
|
|
expectEqual(rebased2.startIndex, 0)
|
|
expectEqual(rebased2.endIndex, 1)
|
|
expectEqual(rebased2[0], slice[i + 1])
|
|
}
|
|
}
|
|
|
|
let rebased3 = ${SelfType}(rebasing: ${SelfType}(start: nil, count: 0)[...])
|
|
expectEqual(rebased3.baseAddress, nil)
|
|
|
|
% if not IsMutable:
|
|
% if IsRaw:
|
|
let rebased4 = ${SelfType}(rebasing: UnsafeMutableRawBufferPointer(start: nil, count: 0)[...])
|
|
expectEqual(rebased4.baseAddress, nil)
|
|
% else:
|
|
let rebased4 = ${SelfType}(rebasing: UnsafeMutableBufferPointer<Float>(start: nil, count: 0)[...])
|
|
expectEqual(rebased4.baseAddress, nil)
|
|
% end # !Raw
|
|
% end # Mutable
|
|
}
|
|
|
|
// Allocate two buffers. Initialize one and copy it into the other. Pass those
|
|
// to the specified generic collection test function `checkBuffers`.
|
|
func checkWithExpectedBuffer(checkBuffers: (${SelfType}, ${SelfType}) -> Void) {
|
|
// A collection just big enough to be sliced up interestingly.
|
|
let elementCount = 4
|
|
|
|
% if IsRaw:
|
|
var memory: UnsafeMutableRawPointer
|
|
var memoryCopy: UnsafeMutableRawPointer
|
|
% else:
|
|
var memory: UnsafeMutablePointer<Float>
|
|
var memoryCopy: UnsafeMutablePointer<Float>
|
|
% end
|
|
|
|
memory = allocateFor${Raw}Buffer(count: elementCount)
|
|
defer { deallocateFor${Raw}Buffer(
|
|
memory, count: elementCount) }
|
|
|
|
memoryCopy = allocateFor${Raw}Buffer(count: elementCount)
|
|
defer { deallocateFor${Raw}Buffer(memoryCopy, count: elementCount) }
|
|
|
|
initUnsafe${Raw}BufferPointer(
|
|
UnsafeMutable${Raw}BufferPointer(start: memory, count: elementCount))
|
|
|
|
let buffer = ${SelfType}(start: memory, count: elementCount)
|
|
|
|
let expectedBuffer = UnsafeMutable${Raw}BufferPointer(start: memoryCopy,
|
|
count: elementCount)
|
|
|
|
% if IsRaw:
|
|
expectedBuffer.copyMemory(from: UnsafeRawBufferPointer(buffer))
|
|
% else:
|
|
_ = expectedBuffer.initialize(from: buffer)
|
|
% end
|
|
|
|
let expected = ${SelfType}(
|
|
start: expectedBuffer.baseAddress, count: expectedBuffer.count)
|
|
|
|
checkBuffers(expected, buffer)
|
|
}
|
|
|
|
${SelfName}TestSuite.test("RandomAccessCollection") {
|
|
checkWithExpectedBuffer { (expected: ${SelfType}, buffer: ${SelfType}) in
|
|
checkRandomAccessCollection(expected, buffer,
|
|
sameValue: { (a: ${Element}, b: ${Element}) in a == b })
|
|
}
|
|
}
|
|
|
|
${SelfName}TestSuite.test("nilBaseAddress") {
|
|
let emptyBuffer = ${SelfType}(start: nil, count: 0)
|
|
expectNil(emptyBuffer.baseAddress)
|
|
expectEqual(0, emptyBuffer.count)
|
|
expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
|
|
|
|
var iter = emptyBuffer.makeIterator()
|
|
expectNil(iter.next())
|
|
|
|
expectEqualSequence([], emptyBuffer)
|
|
}
|
|
|
|
% if IsMutable:
|
|
${SelfName}TestSuite.test("copyFromEmptyBuffer") {
|
|
guard #available(SwiftStdlib 5.7, *) else { return }
|
|
|
|
% if IsRaw:
|
|
var memory: UnsafeMutableRawPointer
|
|
let empty = UnsafeRawBufferPointer(start: nil, count: 0)
|
|
% else:
|
|
var memory: UnsafeMutablePointer<Float>
|
|
let empty = UnsafeBufferPointer<Float>(start: nil, count: 0)
|
|
% end
|
|
|
|
let count = 4
|
|
memory = allocateFor${Raw}Buffer(count: count)
|
|
defer { deallocateFor${Raw}Buffer(memory, count: count) }
|
|
|
|
let buffer = UnsafeMutable${Raw}BufferPointer(start: memory, count: count)
|
|
|
|
% if IsRaw:
|
|
buffer.copyMemory(from: empty)
|
|
% else:
|
|
_ = buffer.initialize(from: empty)
|
|
% end
|
|
}
|
|
% end
|
|
|
|
${SelfName}TestSuite.test("nonNilButEmpty") {
|
|
let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
|
|
defer { emptyAllocated.deallocate() }
|
|
|
|
let emptyBuffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: 0)
|
|
expectEqual(emptyAllocated, emptyBuffer.baseAddress)
|
|
expectEqual(0, emptyBuffer.count)
|
|
expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
|
|
|
|
var iter = emptyBuffer.makeIterator()
|
|
expectNil(iter.next())
|
|
|
|
expectEqualSequence([], emptyBuffer)
|
|
}
|
|
|
|
% if IsRaw:
|
|
${SelfName}TestSuite.test("nonNilNonEmpty") {
|
|
let count = 4
|
|
let allocated = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1)
|
|
defer { allocated.deallocate() }
|
|
let uint8Ptr = allocated.initializeMemory(as: UInt8.self, repeating: 1, count: count)
|
|
uint8Ptr[count - 1] = 2
|
|
|
|
let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1)
|
|
expectEqual(allocated, buffer.baseAddress)
|
|
expectEqual(count - 1, buffer.count)
|
|
expectEqual(count - 1, buffer.endIndex - buffer.startIndex)
|
|
|
|
uint8Ptr[1] = 0
|
|
expectEqual(1, buffer[0])
|
|
expectEqual(0, buffer[1])
|
|
expectEqual(1, buffer[2])
|
|
|
|
var iter = buffer.makeIterator()
|
|
expectEqual(1, iter.next())
|
|
expectEqual(0, iter.next())
|
|
expectEqual(1, iter.next())
|
|
expectNil(iter.next())
|
|
|
|
expectEqualSequence([1, 0, 1], buffer.map { Int($0) })
|
|
|
|
expectEqual(2, uint8Ptr[count-1])
|
|
}
|
|
% else: # !IsRaw
|
|
${SelfName}TestSuite.test("nonNilNonEmpty") {
|
|
let count = 4
|
|
let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
|
|
defer { allocated.deallocate() }
|
|
allocated.initialize(repeating: 1.0, count: count)
|
|
allocated[count - 1] = 2.0
|
|
|
|
let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1)
|
|
expectEqual(allocated, buffer.baseAddress)
|
|
expectEqual(count - 1, buffer.count)
|
|
expectEqual(count - 1, buffer.endIndex - buffer.startIndex)
|
|
|
|
allocated[1] = 0.0
|
|
expectEqual(1.0, buffer[0])
|
|
expectEqual(0.0, buffer[1])
|
|
expectEqual(1.0, buffer[2])
|
|
|
|
var iter = buffer.makeIterator()
|
|
expectEqual(1.0, iter.next())
|
|
expectEqual(0.0, iter.next())
|
|
expectEqual(1.0, iter.next())
|
|
expectNil(iter.next())
|
|
|
|
expectEqualSequence([1.0, 0.0, 1.0], buffer)
|
|
|
|
expectEqual(2.0, allocated[count-1])
|
|
}
|
|
% end # !IsRaw
|
|
|
|
${SelfName}TestSuite.test("badCount")
|
|
.skip(.custom(
|
|
{ _isFastAssertConfiguration() },
|
|
reason: "this trap is not guaranteed to happen in -Ounchecked"))
|
|
.code {
|
|
expectCrashLater()
|
|
|
|
let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
|
|
defer { emptyAllocated.deallocate() }
|
|
|
|
let buffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: -1)
|
|
_ = buffer
|
|
}
|
|
|
|
${SelfName}TestSuite.test("badNilCount")
|
|
.skip(.custom(
|
|
{ _isFastAssertConfiguration() },
|
|
reason: "this trap is not guaranteed to happen in -Ounchecked"))
|
|
.code {
|
|
expectCrashLater()
|
|
|
|
let buffer = ${SelfType}(start: nil, count: 1)
|
|
_ = buffer
|
|
}
|
|
% end # for SelfName, IsRaw, SelfType
|
|
|
|
UnsafeMutableRawBufferPointerTestSuite.test("changeElementViaBuffer") {
|
|
let count = 4
|
|
let allocated = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1)
|
|
defer { allocated.deallocate() }
|
|
let uint8Ptr = allocated.initializeMemory(as: UInt8.self, repeating: 1, count: count)
|
|
uint8Ptr[count-1] = UInt8.max
|
|
|
|
var buffer = UnsafeMutableRawBufferPointer(start: allocated, count: count - 1)
|
|
|
|
buffer[1] = 0
|
|
expectEqual(1, buffer[0])
|
|
expectEqual(0, buffer[1])
|
|
expectEqual(1, buffer[2])
|
|
|
|
expectEqual(1, uint8Ptr[0])
|
|
expectEqual(0, uint8Ptr[1])
|
|
expectEqual(1, uint8Ptr[2])
|
|
expectEqual(UInt8.max, uint8Ptr[count-1])
|
|
|
|
buffer.sort()
|
|
expectEqual(0, buffer[0])
|
|
expectEqual(1, buffer[1])
|
|
expectEqual(1, buffer[2])
|
|
|
|
expectEqual(0, uint8Ptr[0])
|
|
expectEqual(1, uint8Ptr[1])
|
|
expectEqual(1, uint8Ptr[2])
|
|
expectEqual(UInt8.max, uint8Ptr[count-1])
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("changeElementViaBuffer") {
|
|
let count = 4
|
|
let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
|
|
defer { allocated.deallocate() }
|
|
allocated.initialize(repeating: 1.0, count: count)
|
|
allocated[count-1] = -1.0
|
|
|
|
var buffer = UnsafeMutableBufferPointer(start: allocated, count: count - 1)
|
|
|
|
buffer[1] = 0.0
|
|
expectEqual(1.0, buffer[0])
|
|
expectEqual(0.0, buffer[1])
|
|
expectEqual(1.0, buffer[2])
|
|
|
|
expectEqual(1.0, allocated[0])
|
|
expectEqual(0.0, allocated[1])
|
|
expectEqual(1.0, allocated[2])
|
|
expectEqual(-1.0, allocated[count-1])
|
|
|
|
buffer.sort()
|
|
expectEqual(0.0, buffer[0])
|
|
expectEqual(1.0, buffer[1])
|
|
expectEqual(1.0, buffer[2])
|
|
|
|
expectEqual(0.0, allocated[0])
|
|
expectEqual(1.0, allocated[1])
|
|
expectEqual(1.0, allocated[2])
|
|
expectEqual(-1.0, allocated[count-1])
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("withContiguous(Mutable)StorageIfAvailable") {
|
|
let count = 4
|
|
let allocated = UnsafeMutablePointer<Int>.allocate(capacity: count)
|
|
defer { allocated.deallocate() }
|
|
allocated.initialize(repeating: 1, count: count)
|
|
|
|
var mutableBuffer = UnsafeMutableBufferPointer(start: allocated, count: count)
|
|
let executed: ()? = mutableBuffer.withContiguousMutableStorageIfAvailable { buf in
|
|
for i in 0..<buf.count { buf[i] *= 2 }
|
|
}
|
|
expectNotNil(executed)
|
|
let result1 = mutableBuffer.withContiguousStorageIfAvailable { buf in
|
|
return buf.reduce(0, +)
|
|
}
|
|
expectEqual(count*2, result1)
|
|
|
|
let immutableBuffer = UnsafeBufferPointer(start: allocated, count: count)
|
|
let result2 = immutableBuffer.withContiguousStorageIfAvailable { buf in
|
|
return buf.reduce(0, +)
|
|
}
|
|
expectEqual(result1, result2)
|
|
}
|
|
|
|
UnsafeMutableRawBufferPointerTestSuite.test("withContiguous(Mutable)StorageIfAvailable") {
|
|
for c in [0, 1, 4] {
|
|
let pointer = UnsafeMutableRawPointer.allocate(byteCount: c, alignment: c)
|
|
defer { pointer.deallocate() }
|
|
|
|
let mutableBuffer = UnsafeMutableRawBufferPointer(start: pointer, count: c)
|
|
mutableBuffer.copyBytes(from: 0..<UInt8(c))
|
|
|
|
let r: ()? = mutableBuffer.withContiguousMutableStorageIfAvailable {
|
|
for i in $0.indices { $0[i] = 2*($0[i]+1) }
|
|
}
|
|
expectNotNil(r)
|
|
let s = mutableBuffer.withContiguousStorageIfAvailable {
|
|
$0.reduce(0, +)
|
|
}
|
|
expectEqual(s.map(Int.init), c*(c+1))
|
|
|
|
let immutableBuffer = UnsafeRawBufferPointer(mutableBuffer)
|
|
let t = immutableBuffer.withContiguousStorageIfAvailable {
|
|
$0.reduce(0, +)
|
|
}
|
|
expectEqual(s, t)
|
|
}
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("initialize(from: Slice)") {
|
|
let o = 91
|
|
let c = 1_000
|
|
let a = Slice(base: Array(0..<c), bounds: o..<c)
|
|
|
|
let buffer = UnsafeMutableBufferPointer<Int>.allocate(capacity: c-o)
|
|
defer { buffer.deallocate() }
|
|
|
|
var (iterator, copied) = buffer.initialize(from: a)
|
|
expectEqual(iterator.next(), nil)
|
|
expectEqual(copied, c-o)
|
|
|
|
let t = buffer.indices.randomElement()!
|
|
expectEqual(a[t+o], buffer[t])
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("Slice.withContiguousStorageIfAvailable") {
|
|
guard #available(SwiftStdlib 5.3, *) else {
|
|
return
|
|
}
|
|
|
|
for test in subscriptRangeTests {
|
|
let c = test.collection.map { MinimalEquatableValue($0.value) }
|
|
let buffer = UnsafeMutableBufferPointer<MinimalEquatableValue>.allocate(
|
|
capacity: test.collection.count)
|
|
defer { buffer.deallocate() }
|
|
var (it, idx) = buffer.initialize(from: c)
|
|
expectEqual(buffer.endIndex, idx)
|
|
expectNil(it.next())
|
|
|
|
let expected = test.expected.map { MinimalEquatableValue($0.value) }
|
|
let r1: Void? = buffer[test.bounds].withContiguousStorageIfAvailable { b in
|
|
expectTrue(expected.elementsEqual(b))
|
|
}
|
|
expectNotNil(r1)
|
|
let r2: Void? = buffer[test.bounds].withContiguousMutableStorageIfAvailable { b in
|
|
expectTrue(expected.elementsEqual(b))
|
|
}
|
|
expectNotNil(r2)
|
|
}
|
|
}
|
|
|
|
UnsafeMutableRawBufferPointerTestSuite.test("Slice.withContiguousStorageIfAvailable") {
|
|
guard #available(SwiftStdlib 5.7, *) else { return }
|
|
|
|
for test in subscriptRangeTests {
|
|
let c = test.collection.map({ UInt8($0.value/1000) })
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(
|
|
byteCount: test.collection.count, alignment: 8
|
|
)
|
|
defer { buffer.deallocate() }
|
|
buffer.copyBytes(from: c)
|
|
|
|
let expected = test.expected.map({ UInt8($0.value/1000) })
|
|
let r1: ()? = buffer[test.bounds].withContiguousStorageIfAvailable {
|
|
expectTrue(expected.elementsEqual($0))
|
|
}
|
|
expectNotNil(r1)
|
|
let r2: ()? = buffer[test.bounds].withContiguousMutableStorageIfAvailable {
|
|
for i in $0.indices { $0[i] += 1 }
|
|
}
|
|
expectNotNil(r2)
|
|
expectTrue(buffer[test.bounds].elementsEqual(expected.map({ $0+1 })))
|
|
}
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("sort") {
|
|
var values = (0..<1000).map({ _ in Int.random(in: 0..<100) })
|
|
let sortedValues = values.sorted()
|
|
values.withUnsafeMutableBufferPointer { buffer in
|
|
buffer.sort()
|
|
}
|
|
expectEqual(values, sortedValues)
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("partition") {
|
|
var values = (0..<1000).map({ _ in Int.random(in: 0..<100) })
|
|
let partitionIndex = values.withUnsafeMutableBufferPointer { buffer in
|
|
return buffer.partition(by: { $0 % 2 == 0 })
|
|
}
|
|
expectTrue(values[..<partitionIndex].allSatisfy({ $0 % 2 != 0 }))
|
|
expectTrue(values[partitionIndex...].allSatisfy({ $0 % 2 == 0 }))
|
|
}
|
|
|
|
let bufCount = 4
|
|
let sliceRange: Range = 1..<bufCount-1
|
|
% for mutable in [True, False]:
|
|
% for raw in [True, False]:
|
|
% for action in ['read', 'change']:
|
|
% if action != 'change' or mutable:
|
|
for testIndex in (0..<bufCount) {
|
|
% Type = 'Unsafe' + ('Mutable' if mutable else '') + ('Raw' if raw else '') + 'BufferPointer'
|
|
${Type}TestSuite.test("${action}Element\(testIndex)ViaSlice") {
|
|
% if raw:
|
|
let allocated = UnsafeMutableRawPointer.allocate(byteCount: bufCount, alignment: 8)
|
|
for i in 0..<bufCount {
|
|
allocated.storeBytes(of: UInt8(i), toByteOffset: i, as: UInt8.self)
|
|
}
|
|
% else:
|
|
let allocated = UnsafeMutablePointer<Int>.allocate(capacity: bufCount)
|
|
for i in 0..<bufCount { allocated[i] = i }
|
|
% end # if mutable
|
|
defer { allocated.deallocate() }
|
|
|
|
let buffer = ${Type}(start: allocated, count: bufCount)
|
|
${'var' if mutable and action != 'read' else 'let'} slice = buffer[sliceRange]
|
|
|
|
if _isDebugAssertConfiguration(),
|
|
testIndex < sliceRange.lowerBound ||
|
|
testIndex >= sliceRange.upperBound {
|
|
expectCrashLater()
|
|
}
|
|
% if action == 'read':
|
|
let value = slice[testIndex]
|
|
expectEqual(buffer[testIndex], value)
|
|
% else:
|
|
slice[testIndex] = 103
|
|
expectEqual(buffer[testIndex], 103)
|
|
% end # if action
|
|
}
|
|
}
|
|
% end # if action or mutable
|
|
% end # for action
|
|
% end # for raw
|
|
% end # for mutable
|
|
|
|
let testRanges = (0..<bufCount-1).map({ i -> Range<Int> in i..<i+2 })
|
|
% for mutable in [True, False]:
|
|
% for raw in [True, False]:
|
|
% for action in ['read', 'change']:
|
|
% if action != 'change' or mutable:
|
|
for testRange in testRanges {
|
|
% Type = 'Unsafe' + ('Mutable' if mutable else '') + ('Raw' if raw else '') + 'BufferPointer'
|
|
${Type}TestSuite.test("${action}Slice\(testRange)ViaSlice") {
|
|
% if raw:
|
|
let allocated = UnsafeMutableRawPointer.allocate(byteCount: bufCount+2, alignment: 8)
|
|
for i in 0..<bufCount+2 {
|
|
allocated.storeBytes(of: UInt8(i), toByteOffset: i, as: UInt8.self)
|
|
}
|
|
% else:
|
|
let allocated = UnsafeMutablePointer<Int>.allocate(capacity: bufCount+2)
|
|
for i in 0..<bufCount+2 { allocated[i] = i }
|
|
% end # if mutable
|
|
defer { allocated.deallocate() }
|
|
|
|
let buffer = ${Type}(start: allocated, count: bufCount+2)
|
|
${'var' if mutable and action != 'read' else 'let'} slice = buffer[sliceRange]
|
|
|
|
if _isDebugAssertConfiguration(),
|
|
testRange.lowerBound < sliceRange.lowerBound ||
|
|
testRange.upperBound > sliceRange.upperBound {
|
|
expectCrashLater()
|
|
}
|
|
|
|
% if action == 'read':
|
|
let value = slice[testRange]
|
|
expectEqualSequence(buffer[testRange], value)
|
|
% else:
|
|
let sourceSlice = buffer[bufCount..<bufCount+2]
|
|
slice[testRange] = sourceSlice
|
|
expectEqualSequence(buffer[testRange], sourceSlice)
|
|
% end # if action
|
|
}
|
|
}
|
|
% end # if action or mutable
|
|
% end # for action
|
|
% end # for raw
|
|
% end # for mutable
|
|
|
|
protocol SubscriptTest {
|
|
static var start: Int { get }
|
|
static var end: Int { get }
|
|
static var elementCount: Int { get }
|
|
}
|
|
|
|
// Initialize memory with opaque values, for use with subscript tests.
|
|
extension SubscriptTest {
|
|
static var elementCount: Int { get { return end - start } }
|
|
|
|
% for SelfType in ['UnsafeRawBufferPointer', 'UnsafeMutableRawBufferPointer']:
|
|
/// Create and populate an `${SelfType}` for use with unit tests.
|
|
/// PRECONDITION: `memory` must be allocated with space for
|
|
/// `SubscriptGetTest.elementCount` bytes.
|
|
static func create${SelfType}(from memory: UnsafeMutableRawPointer)
|
|
-> ${SelfType}
|
|
{
|
|
for i in Self.start..<Self.end {
|
|
(memory + i * MemoryLayout<UInt8>.stride).initializeMemory(as: UInt8.self, repeating: numericCast(i), count: 1)
|
|
}
|
|
return ${SelfType}(start: memory, count: Self.elementCount)
|
|
}
|
|
% end
|
|
|
|
% for SelfType in ['UnsafeBufferPointer', 'UnsafeMutableBufferPointer']:
|
|
/// Create and populate an `${SelfType}` for use with unit tests.
|
|
/// PRECONDITION: `memory` must be allocated with space for
|
|
/// `SubscriptGetTest.elementCount` elements.
|
|
static func create${SelfType}(from memory: UnsafeMutablePointer<OpaqueValue<Int>>)
|
|
-> ${SelfType}<OpaqueValue<Int>>
|
|
{
|
|
for i in Self.start..<Self.end {
|
|
memory[i] = OpaqueValue(i)
|
|
}
|
|
return ${SelfType}(start: memory, count: Self.elementCount)
|
|
}
|
|
% end
|
|
}
|
|
|
|
struct SubscriptGetTest : SubscriptTest {
|
|
// SubscriptGetTest operates on a `(end - start)` sized buffer containing
|
|
// monotonically increasing integers from `start` to `end - 1`.
|
|
static var start = 0
|
|
static var end = 20
|
|
|
|
let rangeSelection: RangeSelection
|
|
/// The values that should be expected by slicing the UBP, or `nil` if the
|
|
/// test is expected to crash.
|
|
let expectedValues: [Int]?
|
|
/// Same as `expectedValues`, but for closed ranges. `nil` if no difference,
|
|
/// and empty if the test is expected to crash.
|
|
let expectedClosedValues: [Int]?
|
|
|
|
let loc: SourceLoc
|
|
|
|
init(
|
|
rangeSelection: RangeSelection, expectedValues: [Int]? = nil,
|
|
expectedClosedValues: [Int]? = nil,
|
|
file: String = #file, line: UInt = #line
|
|
) {
|
|
self.rangeSelection = rangeSelection
|
|
self.expectedValues = expectedValues
|
|
self.expectedClosedValues = expectedClosedValues ?? expectedValues
|
|
self.loc = SourceLoc(file, line, comment: "test data")
|
|
}
|
|
}
|
|
|
|
let subscriptGetTests : [SubscriptGetTest] = [
|
|
// Valid, empty.
|
|
SubscriptGetTest(rangeSelection: .emptyRange, expectedValues: []),
|
|
|
|
// Valid, edges.
|
|
SubscriptGetTest(rangeSelection: .leftEdge,
|
|
expectedValues: [],
|
|
expectedClosedValues: [0]),
|
|
SubscriptGetTest(rangeSelection: .rightEdge,
|
|
expectedValues: [],
|
|
expectedClosedValues: [19]),
|
|
|
|
// Valid, internal.
|
|
SubscriptGetTest(rangeSelection: .leftHalf,
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
SubscriptGetTest(rangeSelection: .rightHalf,
|
|
expectedValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
|
SubscriptGetTest(rangeSelection: .middle,
|
|
expectedValues: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
|
|
SubscriptGetTest(rangeSelection: .full,
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
|
SubscriptGetTest(rangeSelection: .offsets(2, 4),
|
|
expectedValues: [2, 3],
|
|
expectedClosedValues: [2, 3, 4]),
|
|
SubscriptGetTest(rangeSelection: .offsets(16, 19),
|
|
expectedValues: [16, 17, 18],
|
|
expectedClosedValues: [16, 17, 18, 19]),
|
|
|
|
// Invalid, bottom out of bounds.
|
|
SubscriptGetTest(rangeSelection: .offsets(-1, -1)),
|
|
SubscriptGetTest(rangeSelection: .offsets(-1, 0)),
|
|
SubscriptGetTest(rangeSelection: .offsets(-100, 5)),
|
|
|
|
// Invalid, top out of bounds.
|
|
SubscriptGetTest(rangeSelection: .offsets(20, 20),
|
|
expectedValues: []), // Only crash on a closed range.
|
|
SubscriptGetTest(rangeSelection: .offsets(19, 20),
|
|
expectedValues: [19],
|
|
expectedClosedValues: []), // Only crash on a closed range
|
|
SubscriptGetTest(rangeSelection: .offsets(21, 21)),
|
|
SubscriptGetTest(rangeSelection: .offsets(5, 100)),
|
|
|
|
// Invalid, both out of bounds.
|
|
SubscriptGetTest(rangeSelection: .offsets(-1, 20)),
|
|
SubscriptGetTest(rangeSelection: .offsets(-100, 100)),
|
|
]
|
|
|
|
struct SubscriptSetTest : SubscriptTest {
|
|
// SubscriptSetTest operates on a `(end - start)` sized buffer containing
|
|
// monotonically increasing integers from `start` to `end - 1`.
|
|
static var start = 0
|
|
static var end = 10
|
|
|
|
let rangeSelection: RangeSelection
|
|
|
|
let replacementValues: [OpaqueValue<Int>]
|
|
let replacementClosedValues: [OpaqueValue<Int>]
|
|
|
|
/// The values that should be expected by slicing the UBP, or `nil` if the
|
|
/// test is expected to crash.
|
|
let expectedValues: [Int]?
|
|
/// Same as `expectedValues`, but for closed ranges. `nil` if no difference.
|
|
let expectedClosedValues: [Int]?
|
|
|
|
let loc: SourceLoc
|
|
|
|
init(
|
|
rangeSelection: RangeSelection,
|
|
replacementValues: [Int],
|
|
replacementClosedValues: [Int]? = nil,
|
|
expectedValues: [Int]? = nil,
|
|
expectedClosedValues: [Int]? = nil,
|
|
file: String = #file, line: UInt = #line
|
|
) {
|
|
self.rangeSelection = rangeSelection
|
|
self.expectedValues = expectedValues
|
|
self.expectedClosedValues = expectedClosedValues ?? expectedValues
|
|
|
|
self.replacementValues = replacementValues.map { OpaqueValue($0) }
|
|
if let replacements = replacementClosedValues {
|
|
self.replacementClosedValues = replacements.map { OpaqueValue($0) }
|
|
} else {
|
|
self.replacementClosedValues = self.replacementValues
|
|
}
|
|
self.loc = SourceLoc(file, line, comment: "test data")
|
|
}
|
|
|
|
/// Create and populate an UnsafeMutableRawBufferPointer slice for use with
|
|
/// unit tests.
|
|
/// PRECONDITION: `memory` must be allocated with space for
|
|
/// `replacementValues.count` bytes.
|
|
func replacementValuesSlice(
|
|
from memory: UnsafeMutableRawPointer,
|
|
replacementValues: [OpaqueValue<Int>]
|
|
) -> UnsafeMutableRawBufferPointer.SubSequence
|
|
{
|
|
for (i, value) in replacementValues.enumerated() {
|
|
(memory + i * MemoryLayout<UInt8>.stride).initializeMemory(
|
|
as: UInt8.self, repeating: numericCast(value.value), count: 1)
|
|
}
|
|
let buffer = UnsafeMutableRawBufferPointer(
|
|
start: memory, count: replacementValues.count)
|
|
let fullRange = RangeSelection.full.range(in: buffer)
|
|
return buffer[fullRange]
|
|
}
|
|
|
|
/// Create and populate an UnsafeMutableBufferPointer slice for use with unit
|
|
/// tests.
|
|
/// PRECONDITION: `memory` must be allocated with space for
|
|
/// `replacementValues.count` elements.
|
|
func replacementValuesSlice(
|
|
from memory: UnsafeMutablePointer<OpaqueValue<Int>>,
|
|
replacementValues: [OpaqueValue<Int>]
|
|
) -> Slice<UnsafeMutableBufferPointer<OpaqueValue<Int>>>
|
|
{
|
|
for (i, value) in replacementValues.enumerated() {
|
|
memory[i] = value
|
|
}
|
|
let buffer = UnsafeMutableBufferPointer(
|
|
start: memory, count: replacementValues.count)
|
|
let fullRange = RangeSelection.full.range(in: buffer)
|
|
return buffer[fullRange]
|
|
}
|
|
}
|
|
|
|
let subscriptSetTests : [SubscriptSetTest] = [
|
|
// Valid, empty.
|
|
SubscriptSetTest(
|
|
rangeSelection: .emptyRange,
|
|
replacementValues: [],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
|
|
// Valid, edges.
|
|
SubscriptSetTest(
|
|
rangeSelection: .leftEdge,
|
|
replacementValues: [],
|
|
replacementClosedValues: [91],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
expectedClosedValues: [91, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .rightEdge,
|
|
replacementValues: [],
|
|
replacementClosedValues: [91],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
expectedClosedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 91]),
|
|
|
|
// Valid, internal.
|
|
SubscriptSetTest(
|
|
rangeSelection: .leftHalf,
|
|
replacementValues: [10, 11, 12, 13, 14],
|
|
expectedValues: [10, 11, 12, 13, 14, 5, 6, 7, 8, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .rightHalf,
|
|
replacementValues: [10, 11, 12, 13, 14],
|
|
expectedValues: [0, 1, 2, 3, 4, 10, 11, 12, 13, 14]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .middle,
|
|
replacementValues: [10, 11, 12, 13, 14, 15],
|
|
expectedValues: [0, 1, 10, 11, 12, 13, 14, 15, 8, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .full,
|
|
replacementValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
|
|
expectedValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
|
|
|
// Invalid, range and replacement count mismatch.
|
|
SubscriptSetTest(
|
|
rangeSelection: .leftEdge,
|
|
replacementValues: [9, 9],
|
|
replacementClosedValues: [9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(1, 2),
|
|
replacementValues: [],
|
|
replacementClosedValues: [9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(1, 2),
|
|
replacementValues: [9, 9],
|
|
replacementClosedValues: [9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(2, 5),
|
|
replacementValues: [9, 9],
|
|
replacementClosedValues: [9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(2, 5),
|
|
replacementValues: [9, 9, 9, 9],
|
|
replacementClosedValues: [9, 9, 9, 9, 9]),
|
|
|
|
// Invalid, bottom out of bounds.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-1, -1),
|
|
replacementValues: []),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-1, 0),
|
|
replacementValues: [9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-3, 5),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9, 9]),
|
|
|
|
// Invalid, top out of bounds.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(10, 10),
|
|
replacementValues: [],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
expectedClosedValues: []), // Only crash on a closed range.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(9, 10),
|
|
replacementValues: [91],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 91],
|
|
expectedClosedValues: []), // Only crash on a closed range.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(11, 11),
|
|
replacementValues: []),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(8, 15),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9]),
|
|
|
|
// Invalid, both out of bounds.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-1, 10),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-2, 11),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]),
|
|
]
|
|
|
|
% for (SelfName, IsRaw) in [
|
|
% ('UnsafeBufferPointer', False),
|
|
% ('UnsafeRawBufferPointer', True),
|
|
% ('UnsafeMutableBufferPointer', False),
|
|
% ('UnsafeMutableRawBufferPointer', True)
|
|
% ]:
|
|
|
|
% Raw = 'Raw' if IsRaw else ''
|
|
|
|
% for RangeName in ['range', 'closedRange']:
|
|
${SelfName}TestSuite.test("subscript/${RangeName}/get").forEach(in: subscriptGetTests) {
|
|
(test) in
|
|
|
|
let expectedValues: [Int]?
|
|
% if 'closed' in RangeName.lower():
|
|
if test.rangeSelection.isEmpty {
|
|
return
|
|
}
|
|
// Treat an empty set as nil for closed ranges.
|
|
if test.expectedClosedValues?.isEmpty ?? true {
|
|
expectedValues = nil
|
|
}
|
|
else {
|
|
expectedValues = test.expectedClosedValues
|
|
}
|
|
% else:
|
|
expectedValues = test.expectedValues
|
|
% end
|
|
|
|
let elementCount = SubscriptGetTest.elementCount
|
|
|
|
% if IsRaw:
|
|
var memory: UnsafeMutableRawPointer
|
|
% else:
|
|
var memory: UnsafeMutablePointer<OpaqueValue<Int>>
|
|
% end
|
|
|
|
memory = allocateFor${Raw}Buffer(count: elementCount)
|
|
defer { deallocateFor${Raw}Buffer(memory, count: elementCount) }
|
|
|
|
let buffer = SubscriptGetTest.create${SelfName}(from: memory)
|
|
|
|
% if IsRaw:
|
|
// A raw buffer pointer has debug bounds checks on indices, and
|
|
// (currently) invokes Collection._failEarlyRangeCheck in nondebug mode.
|
|
if expectedValues == nil { expectCrashLater() }
|
|
% end
|
|
let range = test.rangeSelection.${RangeName}(in: buffer)
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
if expectedValues == nil { expectCrashLater() }
|
|
}
|
|
let slice = buffer[range]
|
|
// If expectedValues is nil, we should have crashed above. Allowing the
|
|
// following code to crash leads to false positives.
|
|
if let expectedValues = expectedValues {
|
|
expectEqual(
|
|
expectedValues,
|
|
% if IsRaw:
|
|
slice.map { Int($0) },
|
|
% else:
|
|
slice.map { $0.value },
|
|
% end
|
|
stackTrace: SourceLocStack().with(test.loc)
|
|
)
|
|
}
|
|
}
|
|
|
|
% end # RangeName
|
|
% end # SelfName, IsMutable, IsRaw, SelfType, PointerType
|
|
|
|
% for (SelfName, IsRaw) in [
|
|
% ('UnsafeMutableBufferPointer', False),
|
|
% ('UnsafeMutableRawBufferPointer', True)
|
|
% ]:
|
|
% Raw = 'Raw' if IsRaw else ''
|
|
% for RangeName in ['range', 'closedRange']:
|
|
|
|
UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/${RangeName}/set")
|
|
% if not IsRaw:
|
|
// UnsafeRawBuffer (currently) invokes Collection._failEarlyRangeCheck
|
|
// in nondebug mode.
|
|
.skip(.custom(
|
|
{ !_isDebugAssertConfiguration() },
|
|
reason: "This tests a debug precondition."))
|
|
% end
|
|
.forEach(in: subscriptSetTests) { (test) in
|
|
|
|
let expectedValues: [Int]?
|
|
let replacementValues: [OpaqueValue<Int>]
|
|
let elementCount = SubscriptSetTest.elementCount
|
|
|
|
% if 'closed' in RangeName.lower():
|
|
if test.rangeSelection.isEmpty {
|
|
return
|
|
}
|
|
// Treat an empty set as nil for closed ranges.
|
|
if test.expectedClosedValues?.isEmpty ?? true {
|
|
expectedValues = nil
|
|
}
|
|
else {
|
|
expectedValues = test.expectedClosedValues
|
|
}
|
|
replacementValues = test.replacementClosedValues
|
|
let isOutOfBounds: () -> Bool = {
|
|
switch test.rangeSelection {
|
|
case let .offsets(lowerBound, upperBound):
|
|
return lowerBound < 0 || upperBound >= elementCount
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
% else: # !closed
|
|
expectedValues = test.expectedValues
|
|
replacementValues = test.replacementValues
|
|
let isOutOfBounds: () -> Bool = {
|
|
switch test.rangeSelection {
|
|
case let .offsets(lowerBound, upperBound):
|
|
return lowerBound < 0 || upperBound > elementCount
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
% end # !closed
|
|
|
|
% if IsRaw:
|
|
var memory: UnsafeMutableRawPointer
|
|
var sliceMemory: UnsafeMutableRawPointer
|
|
% else:
|
|
var memory: UnsafeMutablePointer<OpaqueValue<Int>>
|
|
var sliceMemory: UnsafeMutablePointer<OpaqueValue<Int>>
|
|
% end
|
|
|
|
memory = allocateFor${Raw}Buffer(count: elementCount)
|
|
defer { deallocateFor${Raw}Buffer(memory, count: elementCount) }
|
|
|
|
sliceMemory = allocateFor${Raw}Buffer(count: replacementValues.count)
|
|
defer { deallocateFor${Raw}Buffer(
|
|
sliceMemory, count: replacementValues.count) }
|
|
|
|
% if RangeName == 'range':
|
|
let buffer = SubscriptSetTest.create${SelfName}(from: memory)
|
|
% else:
|
|
var buffer = SubscriptSetTest.create${SelfName}(from: memory)
|
|
% end
|
|
|
|
% if IsRaw:
|
|
// A raw buffer pointer has debug bounds checks on indices, and
|
|
// (currently) invokes Collection._failEarlyRangeCheck in nondebug mode.
|
|
if _isDebugAssertConfiguration() || isOutOfBounds() {
|
|
if expectedValues == nil { expectCrashLater() }
|
|
}
|
|
% else:
|
|
_ = isOutOfBounds
|
|
% end
|
|
let range = test.rangeSelection.${RangeName}(in: buffer)
|
|
|
|
let replacementSlice = test.replacementValuesSlice(
|
|
from: sliceMemory,
|
|
replacementValues: replacementValues)
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
if expectedValues == nil { expectCrashLater() }
|
|
}
|
|
buffer[range] = replacementSlice
|
|
// If expectedValues is nil, we should have crashed above. Allowing the
|
|
// following code to crash leads to false positives.
|
|
if let expectedValues = expectedValues {
|
|
expectEqual(
|
|
expectedValues,
|
|
% if IsRaw:
|
|
buffer.map { Int($0) },
|
|
% else:
|
|
buffer.map { $0.value },
|
|
% end
|
|
stackTrace: SourceLocStack().with(test.loc)
|
|
)
|
|
}
|
|
}
|
|
|
|
% end # RangeName
|
|
|
|
UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/set/overlaps") {
|
|
% if IsRaw:
|
|
let buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: 4, alignment: 1)
|
|
% else:
|
|
let buffer = UnsafeMutableBufferPointer<Int>.allocate(capacity: 4)
|
|
% end
|
|
defer { buffer.deallocate() }
|
|
|
|
// Right Overlap
|
|
buffer[0] = 1
|
|
buffer[1] = 2
|
|
buffer[1..<3] = buffer[0..<2]
|
|
expectEqual(1, buffer[1])
|
|
expectEqual(2, buffer[2])
|
|
// Left Overlap
|
|
buffer[1] = 2
|
|
buffer[2] = 3
|
|
buffer[0..<2] = buffer[1..<3]
|
|
expectEqual(2, buffer[0])
|
|
expectEqual(3, buffer[1])
|
|
// Disjoint
|
|
buffer[2] = 2
|
|
buffer[3] = 3
|
|
buffer[0..<2] = buffer[2..<4]
|
|
expectEqual(2, buffer[0])
|
|
expectEqual(3, buffer[1])
|
|
buffer[0] = 0
|
|
buffer[1] = 1
|
|
buffer[2..<4] = buffer[0..<2]
|
|
expectEqual(0, buffer[2])
|
|
expectEqual(1, buffer[3])
|
|
}
|
|
|
|
UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("nonmutating-swapAt") {
|
|
% if IsRaw:
|
|
let allocated = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 8)
|
|
let buffer = UnsafeMutableRawBufferPointer(start: allocated, count: 3)
|
|
allocated.storeBytes(of: UInt8.max, toByteOffset: 3, as: UInt8.self)
|
|
% else:
|
|
let allocated = UnsafeMutablePointer<Int>.allocate(capacity: 4)
|
|
let buffer = UnsafeMutableBufferPointer(start: allocated, count: 3)
|
|
allocated[3] = Int.max
|
|
% end
|
|
defer { allocated.deallocate() }
|
|
|
|
buffer[0] = 0
|
|
buffer[1] = 1
|
|
buffer[2] = 2
|
|
|
|
buffer.swapAt(0, 0)
|
|
expectEqual(Array(buffer), [0, 1, 2])
|
|
|
|
buffer.swapAt(0, 2)
|
|
expectEqual(Array(buffer), [2, 1, 0])
|
|
|
|
if _isDebugAssertConfiguration() {
|
|
expectCrashLater()
|
|
}
|
|
buffer.swapAt(2, 3)
|
|
}
|
|
|
|
% if not IsRaw:
|
|
UnsafeMutableBufferPointerTestSuite.test("nonmutating-swapAt-withARC") {
|
|
let buffer = UnsafeMutableBufferPointer<String>.allocate(capacity: 3)
|
|
defer { buffer.deallocate() }
|
|
|
|
_ = buffer.initialize(from: (0..<3).map(String.init(describing:)))
|
|
|
|
buffer.swapAt(0, 0)
|
|
expectEqual(Array(buffer), ["0", "1", "2"])
|
|
|
|
buffer.swapAt(0, 2)
|
|
expectEqual(Array(buffer), ["2", "1", "0"])
|
|
}
|
|
% end
|
|
|
|
% end # SelfName
|
|
|
|
% for mutable in [True, False]:
|
|
% TypedName = 'UnsafeMutableBufferPointer' if mutable else 'UnsafeBufferPointer'
|
|
Unsafe${'Mutable' if mutable else ''}BufferPointerTestSuite.test("withMemoryRebound") {
|
|
// test withMemoryRebound behaviour, post SE-0333.
|
|
let mutableBufferI = UnsafeMutableBufferPointer<Int>.allocate(capacity: 4)
|
|
defer { mutableBufferI.deallocate() }
|
|
let ptrI = ${'mutableBufferI' if mutable else TypedName + '(mutableBufferI)'}
|
|
// test rebinding to a wider type with the same alignment
|
|
ptrI.withMemoryRebound(to: (Int, Int).self) {
|
|
// Make sure the closure argument is a ${TypedName}
|
|
let ptrT: ${TypedName}<(Int, Int)> = $0
|
|
expectEqual(ptrT.count, 2)
|
|
// and that the element type is (Int, Int).
|
|
let mutablePtrT = ${'ptrT' if mutable else 'UnsafeMutableBufferPointer(mutating: ptrT)'}
|
|
expectType((Int, Int).self, &mutablePtrT[0])
|
|
// test rebinding to a narrower type
|
|
ptrT.withMemoryRebound(to: UInt.self) {
|
|
// Make sure the closure argument is a ${TypedName}
|
|
let ptrU: ${TypedName}<UInt> = $0
|
|
expectEqual(ptrU.count, 4)
|
|
// and that the element type is UInt.
|
|
let mutablePtrU = ${'ptrU' if mutable else 'UnsafeMutableBufferPointer(mutating: ptrU)'}
|
|
expectType(UInt.self, &mutablePtrU[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
% RawName = 'UnsafeMutableRawBufferPointer' if mutable else 'UnsafeRawBufferPointer'
|
|
Unsafe${'Mutable' if mutable else ''}RawBufferPointerTestSuite.test("withMemoryRebound") {
|
|
// test withMemoryRebound behaviour, post SE-0333.
|
|
let allocated = UnsafeMutableRawBufferPointer.allocate(byteCount: 32, alignment: 8)
|
|
defer { allocated.deallocate() }
|
|
let ptrR = ${'allocated' if mutable else RawName + '(allocated)'}
|
|
ptrR.withMemoryRebound(to: Int.self) {
|
|
// Make sure the closure argument is a ${TypedName}
|
|
let ptrT: ${TypedName}<Int> = $0
|
|
expectEqual(ptrT.count, 32/MemoryLayout<Int>.stride)
|
|
// and that the element type is `Int`.
|
|
let mutablePtrT = ${'ptrT' if mutable else 'UnsafeMutableBufferPointer(mutating: ptrT)'}
|
|
expectType(Int.self, &mutablePtrT[0])
|
|
}
|
|
}
|
|
|
|
% end # mutable
|
|
|
|
UnsafeRawBufferPointerTestSuite.test("assumingMemoryBound") {
|
|
let array = (0..<4).map({ $0 })
|
|
array.withUnsafeBytes({
|
|
let b: UnsafeBufferPointer = $0.assumingMemoryBound(to: Int.self)
|
|
expectEqual(b.count, array.count)
|
|
expectEqual(b[3], array[3])
|
|
})
|
|
var mutableArray = array
|
|
mutableArray.withUnsafeMutableBytes({
|
|
let b: UnsafeMutableBufferPointer = $0.assumingMemoryBound(to: Int.self)
|
|
expectEqual(b.count, array.count)
|
|
for i in b.indices { b[i] += 1 }
|
|
})
|
|
expectEqual(mutableArray[3], array[3]+1)
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("UMBP.initialize.collection.overflow")
|
|
.skip(.custom({
|
|
if #available(SwiftStdlib 5.8, *) { return false } else { return true }
|
|
}, reason: "Requires standard library from Swift 5.8"))
|
|
.code {
|
|
let s = Array<Int>(0..<8)
|
|
let b = UnsafeMutableBufferPointer<Int>.allocate(capacity: s.count-1)
|
|
defer { b.deallocate() }
|
|
expectCrash {
|
|
_ = b.initialize(fromContentsOf: s)
|
|
}
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("UMBP.update.collection.overflow")
|
|
.skip(.custom({
|
|
if #available(SwiftStdlib 5.8, *) { return false } else { return true }
|
|
}, reason: "Requires standard library from Swift 5.8"))
|
|
.code {
|
|
let s = Array(0..<8)
|
|
var b = Array(repeating: 0, count: s.count-1)
|
|
b.withUnsafeMutableBufferPointer { b in
|
|
expectCrash {
|
|
_ = b.update(fromContentsOf: s)
|
|
}
|
|
}
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("UMBP.moveInitialize.overflow")
|
|
.skip(.custom({
|
|
if #available(SwiftStdlib 5.8, *) { return false } else { return true }
|
|
}, reason: "Requires standard library from Swift 5.8"))
|
|
.code {
|
|
let s = UnsafeMutableBufferPointer<Int>.allocate(capacity: 8)
|
|
defer { s.deallocate() }
|
|
s.initialize(fromContentsOf: 0..<s.count)
|
|
|
|
let b = UnsafeMutableBufferPointer<Int>.allocate(capacity: s.count-1)
|
|
defer { b.deallocate() }
|
|
expectCrash {
|
|
_ = b.moveInitialize(fromContentsOf: s)
|
|
}
|
|
}
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("UMBP.moveUpdate.overflow")
|
|
.skip(.custom({
|
|
if #available(SwiftStdlib 5.8, *) { return false } else { return true }
|
|
}, reason: "Requires standard library from Swift 5.8"))
|
|
.code {
|
|
let s = UnsafeMutableBufferPointer<Int>.allocate(capacity: 8)
|
|
defer { s.deallocate() }
|
|
s.initialize(fromContentsOf: 0..<s.count)
|
|
|
|
var b = Array(repeating: 0, count: s.count-1)
|
|
b.withUnsafeMutableBufferPointer { b in
|
|
expectCrash {
|
|
_ = b.moveUpdate(fromContentsOf: s)
|
|
}
|
|
}
|
|
}
|
|
|
|
UnsafeMutableRawBufferPointerTestSuite.test("UMRBP.initializeMemory.collection.overflow")
|
|
.skip(.custom({
|
|
if #available(SwiftStdlib 5.8, *) { return false } else { return true }
|
|
}, reason: "Requires standard library from Swift 5.8"))
|
|
.code {
|
|
let s = Array<Int>(0..<8)
|
|
let b = UnsafeMutableRawBufferPointer.allocate(
|
|
byteCount: MemoryLayout<Int>.stride * (s.count-1),
|
|
alignment: MemoryLayout<Int>.alignment
|
|
)
|
|
defer { b.deallocate() }
|
|
let i = b.initializeMemory(as: Int.self, fromContentsOf: s.dropLast())
|
|
i.deinitialize()
|
|
|
|
expectCrash {
|
|
let i = b.initializeMemory(as: Int.self, fromContentsOf: s)
|
|
i.deinitialize()
|
|
}
|
|
}
|
|
|
|
UnsafeMutableRawBufferPointerTestSuite.test("UMRBP.moveInitializeMemory.overflow")
|
|
.skip(.custom({
|
|
if #available(SwiftStdlib 5.8, *) { return false } else { return true }
|
|
}, reason: "Requires standard library from Swift 5.8"))
|
|
.code {
|
|
let s = UnsafeMutableBufferPointer<Int>.allocate(capacity: 8)
|
|
defer { s.deallocate() }
|
|
s.initialize(fromContentsOf: 0..<s.count)
|
|
|
|
let b = UnsafeMutableRawBufferPointer.allocate(
|
|
byteCount: MemoryLayout<Int>.stride * (s.count-1),
|
|
alignment: MemoryLayout<Int>.alignment
|
|
)
|
|
defer { b.deallocate() }
|
|
expectCrash {
|
|
let i = b.moveInitializeMemory(as: Int.self, fromContentsOf: s)
|
|
i.deinitialize()
|
|
}
|
|
}
|
|
|
|
runAllTests()
|