// 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(count: Int) -> UnsafeMutablePointer { return UnsafeMutablePointer.allocate(capacity: count) } func deallocateForRawBuffer( _ memory: UnsafeMutableRawPointer, count: Int ) { memory.deallocate() } func deallocateForBuffer( _ memory: UnsafeMutablePointer, count: Int ) { memory.deallocate() } // Initialize memory with arbitrary equatable, comparable values. func initUnsafeRawBufferPointer(_ b: UnsafeMutableRawBufferPointer) { _ = b.initializeMemory(as: UInt8.self, from: UInt8(0)..) { _ = b.initialize(from: (0..', 'UnsafePointer'), % ('UnsafeMutableBufferPointer', True, False, 'UnsafeMutableBufferPointer', 'UnsafeMutablePointer'), % ('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.Iterator.self, % end subSequenceType: Slice<${SelfType}>.self, indexType: Int.self, indicesType: Range.self) expect${'Mutable' if IsMutable else ''}CollectionType(${SelfType}.self) } ${SelfName}TestSuite.test("rebasing") { let rawbuffer = UnsafeMutableRawBufferPointer.allocate( byteCount: 4 * MemoryLayout.stride, alignment: MemoryLayout.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.. 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(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 var memoryCopy: UnsafeMutablePointer % 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 let empty = UnsafeBufferPointer(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.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.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.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.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.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...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.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[...allocate(capacity: bufCount) for i in 0..= 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.. Range in i...allocate(capacity: bufCount+2) for i in 0.. sliceRange.upperBound { expectCrashLater() } % if action == 'read': let value = slice[testRange] expectEqualSequence(buffer[testRange], value) % else: let sourceSlice = buffer[bufCount.. ${SelfType} { for i in Self.start...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>) -> ${SelfType}> { for i in Self.start..] let replacementClosedValues: [OpaqueValue] /// 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] ) -> UnsafeMutableRawBufferPointer.SubSequence { for (i, value) in replacementValues.enumerated() { (memory + i * MemoryLayout.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>, replacementValues: [OpaqueValue] ) -> Slice>> { 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> % 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] 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> var sliceMemory: UnsafeMutablePointer> % 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.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.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.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.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} = $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} = $0 expectEqual(ptrT.count, 32/MemoryLayout.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(0..<8) let b = UnsafeMutableBufferPointer.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.allocate(capacity: 8) defer { s.deallocate() } s.initialize(fromContentsOf: 0...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.allocate(capacity: 8) defer { s.deallocate() } s.initialize(fromContentsOf: 0..(0..<8) let b = UnsafeMutableRawBufferPointer.allocate( byteCount: MemoryLayout.stride * (s.count-1), alignment: MemoryLayout.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.allocate(capacity: 8) defer { s.deallocate() } s.initialize(fromContentsOf: 0...stride * (s.count-1), alignment: MemoryLayout.alignment ) defer { b.deallocate() } expectCrash { let i = b.moveInitializeMemory(as: Int.self, fromContentsOf: s) i.deinitialize() } } runAllTests()