mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This removes a bunch of overhead on the UTF16 paths in String, as well as consolidating the complicated bits of the logic in one file.
1300 lines
42 KiB
Swift
1300 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() }
|
|
|
|
// Make sure we can't emit the error at compile time
|
|
@inline(never) var badCount: Int { -1 }
|
|
|
|
let buffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: badCount)
|
|
_ = 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()
|